简体   繁体   English

JRuby PermGen。 记不清。 堆空间内存泄漏

[英]JRuby PermGen. Out of memory. Heap space memory leaks

We are working on a big project. 我们正在做一个大项目。 During our development we faced with a big a problem related to Heap and PermGen Space. 在我们的开发过程中,我们遇到了一个与堆和PermGen空间有关的大问题。 Here our error message: Current error: java.lang.OutOfMemoryError: PermGen space. 这是我们的错误消息:当前错误:java.lang.OutOfMemoryError:PermGen空间。

System.out.println("Initialazing..");
//Spring applicaton context
WebApplicationContext wac = (WebApplicationContext) AppContext.getApplicationContext();
// prepare path to internal ruby 
String scriptsPath = wac.getServletContext().getRealPath(RUBY_PATH);
String jrubyHome = wac.getServletContext().getRealPath("WEB-INF" + File.separator + "jruby");
// Initializing Scripting container
ScriptingContainer container = new ScriptingContainer(isShared ? LocalContextScope.SINGLETHREAD
                : LocalContextScope.THREADSAFE, LocalVariableBehavior.PERSISTENT);
// Configuring scriptingcontainer to avoid memory leaks
container.setCompileMode(RubyInstanceConfig.CompileMode.OFF);
System.setProperty("org.jruby.embed.compilemode", "OFF");
System.setProperty("jruby.compile.mode", "OFF");
// Setup ruby version
container.setCompatVersion(CompatVersion.RUBY1_9);
// Set jruby home
container.getProvider().getRubyInstanceConfig().setJRubyHome(jrubyHome);
List<String> loadPaths = new ArrayList<String>();
// load path
loadPaths.add(scriptsPath);
container.getProvider().setLoadPaths(loadPaths);
// ruby dispatcher initializing and run in simple mood
String fileName = scriptsPath + File.separator + "dispatcher_fake.rb";
// run scriplet
container.runScriptlet(PathType.ABSOLUTE, fileName);
// terminate container to cleanup memory without any effects
container.terminate();
container=null;

Description: above code create and configure Scripting container. 说明:上面的代码创建和配置脚本容器。 This methods running in separate thread. 此方法在单独的线程中运行。 We use 4 threads of ruby runs. 我们使用4条红宝石线。 If we use the same scripting container and call internal scriptlets (call internall methods in java threading) we get issues with ruby variables because it is visible cross threading. 如果我们使用相同的脚本容器并调用内部scriptlet(在Java线程中调用internall方法),则会遇到ruby变量的问题,因为它是可见的交叉线程。

Main issue with JRuby are: growing heap memory space and perm gen memory space. JRuby的主要问题是:增大堆内存空间和perm gen内存空间。 We can't call any system's garbage collection in the ruby code. 我们无法在ruby代码中调用任何系统的垃圾回收。

Bellow you can found simple parts of our scriptlet: Ruby: 在下面,您可以找到我们脚本的简单部分:Ruby:

ENV['GEM_PATH'] = File.expand_path('../../jruby/1.9', __FILE__)
ENV['GEM_HOME'] = File.expand_path('../../jruby/1.9', __FILE__)
ENV['BUNDLE_BIN_PATH'] = File.expand_path('../../jruby/1.9/gems/bundler-1.0.18/bin/bundle', __FILE__)

require 'java'
require 'rubygems'
require "bundler/setup"
require 'yaml'
require 'mechanize'
require 'spreadsheet'
require 'json'
require 'rest-client'
require 'active_support/all'
require 'awesome_print'
require 'csv'
require 'builder'
require 'soap/wsdlDriver' rescue nil
ROOT_DIR = File.dirname(__FILE__)
require File.join(ROOT_DIR, "base", "xsi.rb")


import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element


module JavaListing
  include_package "com.util.listing"
end

class A
  include JavaListing
  def run
    1000.times do |index|
      puts "iterating #{index}"
      prop = JavaListing::Property.new
      prop.proNo = 111
      prop.remoteID = "1111"
      prop.ownerID = "1111"
      prop.advertiserID = "1111"
      prop.title = "Atite"
      prop.summary = "Asummury"
      prop.description = "Adescription"
      # prop.images << JavaListing::Image.new("111", "Acaption")
      prop.lat = 12.23
      prop.lng = 13.21
      #prop.address = JavaListing::Address.new("Acity", "Acountry")
      prop.location = "Alocation"
      prop.policy = JavaListing::Policy.new("AcheckinAt", "AcheckoutAt")
      prop.surfaceArea = "Asurfscearea"
      prop.notes[index] = JavaListing::Note.new("Atitle", "Atext")
      prop.order = "Aorder"
      prop.map = JavaListing::Map.new(true, 14)
      prop.units[index] = JavaListing::Unit.new("Aproptype", 2)
      obj = Nokogiri::XML "<root><elements><element>Application Error  #{index}          </element></elements></root>"

    end
  end
end

A.new.run

The same perm gen with other kinds of scriptlets containers: 与其他种类的scriptlet容器相同的perm gen:

Create properties using JSR223 使用JSR223创建属性

ScripHelperBase.java ScripHelperBase.java

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
Reader reader = null;
String fileName = scriptsPath + File.separator + "dispatcher_java.rb";
try {
    reader = new FileReader(fileName);
} catch (FileNotFoundException ex) {
    Logger.getLogger(ScriptHelperBase.class.getName()).log(Level.SEVERE, null, ex);
}
engine.eval(reader);

Ways to solution 解决方法

  1. List item 项目清单

  2. Increase PermGen space PermGen space was increased to 4Gb. 增加PermGen空间PermGen空间已增加到4Gb。 Soon it became full too. 很快它也变得满满的。

Create properties using BSF 使用BSF创建属性

String fileName = scriptsPath + File.separator + "dispatcher_fake_ruby.rb";
String jrubyhome = "WEB-INF" + File.separator + "jruby";

BSFManager.registerScriptingEngine("jruby", "org.jruby.embed.bsf.JRubyEngine", new String[]{"rb"});
BSFManager manager = new BSFManager();
manager.setClassPath(jrubyhome);

try {
    manager.exec("jruby", fileName, 0, 0, PathType.ABSOLUTE);
} catch (BSFException ex) {
    Logger.getLogger(ScriptHelperBase.class.getName()).log(Level.SEVERE, null, ex);
}

Conclusion: This mean that just increasing available space isn't a solution of this hot problem. 结论:这意味着仅增加可用空间并不能解决此热点问题。

The method described above don't allow to clear needed memory to original state. 上述方法不允许将所需的内存清除为原始状态。 It means that every additional script running still increase filled PermGen space. 这意味着运行的每个其他脚本仍然会增加PermGen的填充空间。

Running system using CompileMode=OFF 使用CompileMode = OFF运行系统

container.setCompileMode(RubyInstanceConfig.CompileMode.OFF);
System.setProperty("org.jruby.embed.compilemode", "OFF");
System.setProperty("jruby.compile.mode", "OFF");

JRuby creates Ruby Proxies for native Java classes you are using - they are new classes created at runtime and by default JVM keeps them in memory for ever. JRuby为您正在使用的本机Java类创建Ruby Proxies-它们是在运行时创建的新类,默认情况下,JVM将它们永久保存在内存中。

Here is solution. 是解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM