重复使用 Groovy 个 Shell 导致 PermGen space 满
Repeated use of Groovy Shells results in PermGen space full
在应用程序中,我重复创建 GroovyShell 的实例并在其上执行自定义脚本。执行此操作时,我遇到 Java 6 和 Java 7 中的 perm gen space 已满且未卸载 classes 的问题。我正在使用 Groovy 2.4.7。可以使用以下代码重现该问题:
import groovy.lang.GroovyShell;
public class Demo {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10000000; i++) {
GroovyShell gs = new GroovyShell();
Object result = gs.evaluate(" 'Hello, World';");
assert result.equals("Hello, World");
}
}
}
我正在使用以下 VM 参数:
-verbose:class -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:-UseParNewGC
当我从上面执行测试时,PermGen 在 2000 多次迭代后已满。另外,手动触发GC也不行。
有什么方法可以强制class卸载或触发GC,以便classes从PermGenspace中移除?
重用 GroovyShell 实例:
import groovy.lang.GroovyShell;
public class Demo {
public static void main(String[] args) throws Exception {
//Create outside the loop
GroovyShell gs = new GroovyShell();
for (int i = 0; i < 10000000; i++) {
Object result = gs.evaluate(" 'Hello, World';");
assert result.equals("Hello, World");
}
}
}
我可以理解,因为我已经为此苦苦挣扎了一段时间。
我实现了 this solution,它在 Java 1.6 中提高了 PermGen 的生命周期,但没有消除核心问题。
出于某种原因,我没有在 Java 8 中看到问题,所以我放弃了尝试变通。 (没有尝试过 Java 7)。
希望你能比我走得更远。
哇哦。耽误。我刚刚给了 this one 一个快速的机会,它似乎工作得很好。但是,您不是直接使用 shell,而是编译一个脚本,然后 运行 脚本(结果相同)。然后叫指定的清洁工。
public static void test() {
for (int i = 0; i < 10000000; i++) {
GroovyShell gs = new GroovyShell();
Script script = gs.parse(" 'Hello, World';");
Object result = script.run();
assert result.equals("Hello, World");
clearAllClassInfo(script.getClass());
}
}
public static void clearAllClassInfo(Class<?> type) {
try {
Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue");
globalClassValue.setAccessible(true);
GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null);
classValueBean.remove(type);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
显然,您可以稍微优化清洁器以消除大量反射。
PermGen 非常平坦:
和 类 正在以轻快的速度卸载:
归功于@BilboDai。
在应用程序中,我重复创建 GroovyShell 的实例并在其上执行自定义脚本。执行此操作时,我遇到 Java 6 和 Java 7 中的 perm gen space 已满且未卸载 classes 的问题。我正在使用 Groovy 2.4.7。可以使用以下代码重现该问题:
import groovy.lang.GroovyShell;
public class Demo {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10000000; i++) {
GroovyShell gs = new GroovyShell();
Object result = gs.evaluate(" 'Hello, World';");
assert result.equals("Hello, World");
}
}
}
我正在使用以下 VM 参数:
-verbose:class -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:-UseParNewGC
当我从上面执行测试时,PermGen 在 2000 多次迭代后已满。另外,手动触发GC也不行。
有什么方法可以强制class卸载或触发GC,以便classes从PermGenspace中移除?
重用 GroovyShell 实例:
import groovy.lang.GroovyShell;
public class Demo {
public static void main(String[] args) throws Exception {
//Create outside the loop
GroovyShell gs = new GroovyShell();
for (int i = 0; i < 10000000; i++) {
Object result = gs.evaluate(" 'Hello, World';");
assert result.equals("Hello, World");
}
}
}
我可以理解,因为我已经为此苦苦挣扎了一段时间。 我实现了 this solution,它在 Java 1.6 中提高了 PermGen 的生命周期,但没有消除核心问题。
出于某种原因,我没有在 Java 8 中看到问题,所以我放弃了尝试变通。 (没有尝试过 Java 7)。
希望你能比我走得更远。
哇哦。耽误。我刚刚给了 this one 一个快速的机会,它似乎工作得很好。但是,您不是直接使用 shell,而是编译一个脚本,然后 运行 脚本(结果相同)。然后叫指定的清洁工。
public static void test() {
for (int i = 0; i < 10000000; i++) {
GroovyShell gs = new GroovyShell();
Script script = gs.parse(" 'Hello, World';");
Object result = script.run();
assert result.equals("Hello, World");
clearAllClassInfo(script.getClass());
}
}
public static void clearAllClassInfo(Class<?> type) {
try {
Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue");
globalClassValue.setAccessible(true);
GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null);
classValueBean.remove(type);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
显然,您可以稍微优化清洁器以消除大量反射。
PermGen 非常平坦:
和 类 正在以轻快的速度卸载:
归功于@BilboDai。