重复使用 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