【发布时间】:2012-03-02 22:24:14
【问题描述】:
我正在尝试在运行时动态加载 JRuby(这样我就可以使用任意 JRuby 安装和版本来执行 Ruby 代码)。我的计划大致是创建一个可以访问jruby.jar 的 ClassLoader,然后使用它来加载必要的 JRuby 运行时等。一切都很好,直到我需要多次执行此操作。如果我销毁第一个 JRuby 运行时,第三个或第四个将导致 OutOfMemory: PermGen 空间。
我已将其简化为一个最小示例。该示例同时使用“直接”API 和JRuby Embed API。 “直接”API 部分被注释掉,但两者都表现出相同的行为:经过几次迭代,PermGen 内存不足。 (使用 JRuby 1.6.7 和 JRuby 1.6.5.1 测试)
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.junit.Test;
public class JRubyInstantiationTeardownTest {
@Test
public void test() throws Exception {
for (int i = 0; i < 100; ++i) {
URL[] urls = new URL[] {
new URL("file://path/to/jruby-1.6.7.jar")
};
ClassLoader cl = new URLClassLoader(urls, this.getClass().getClassLoader());
// "Direct" API
/*
Class<?> klass = cl.loadClass("org.jruby.Ruby");
Method newInstance = klass.getMethod("newInstance");
Method evalScriptlet = klass.getMethod("evalScriptlet", String.class);
Method tearDown = klass.getMethod("tearDown");
Object runtime = newInstance.invoke(null);
System.out.println("have " + runtime);
evalScriptlet.invoke(runtime, "puts 'hello, world'");
tearDown.invoke(runtime);
*/
// JRuby Embed API
Class<?> scriptingContainerClass = cl.loadClass("org.jruby.embed.ScriptingContainer");
Method terminate = scriptingContainerClass.getMethod("terminate");
Method runScriptlet = scriptingContainerClass.getMethod("runScriptlet", String.class);
Object container = scriptingContainerClass.newInstance();
System.out.println("have " + container);
runScriptlet.invoke(container, "puts 'hello, world'");
terminate.invoke(container);
}
}
}
问题:尝试使用 ClassLoader 是否合理?如果是这样,这是 JRuby 中的一个错误,还是我的类加载有问题?
奖励:如果这是 JRuby 中的一个错误,Eclipse 内存分析工具之类的工具如何帮助找到源?我可以打开一个堆转储并查看几个 Ruby 对象(我希望在任何给定时间都不会超过一个),但我不确定如何找出为什么这些对象没有被垃圾收集...
【问题讨论】:
-
您可能应该将链接添加到您的 JRuby 错误报告作为答案并接受它,因为这确实是一个 JRuby 错误。
标签: java ruby memory-leaks jruby classloader