Java 反复使用Groovy外壳会导致PermGen空间被填满

Java 反复使用Groovy外壳会导致PermGen空间被填满,java,groovy,garbage-collection,permgen,Java,Groovy,Garbage Collection,Permgen,在应用程序中,我反复创建GroovyShell实例并在其上执行自定义脚本。在执行此操作时,我遇到了一些问题,Java 6和Java 7中的perm gen空间被填满,而类没有被卸载。我正在使用Groovy 2.4.7。可使用以下代码再现此问题: import groovy.lang.GroovyShell; public class Demo { public static void main(String[] args) throws Exception { fo

在应用程序中,我反复创建GroovyShell实例并在其上执行自定义脚本。在执行此操作时,我遇到了一些问题,Java 6和Java 7中的perm gen空间被填满,而类没有被卸载。我正在使用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");
        }
    }
}
当我从上面执行测试时,经过2000多次迭代后,PermGen就满了。此外,手动触发GC也不起作用


有没有办法在此处强制卸载类或触发GC,以便从PermGen空间中删除类?

重用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");
        }
    }
}
导入groovy.lang.GroovyShell;
公开课演示{
公共静态void main(字符串[]args)引发异常{
//在循环之外创建
GroovyShell gs=新GroovyShell();
对于(int i=0;i<10000000;i++){
Object result=gs.evaluate(“'Hello,World';”);
断言result.equals(“你好,世界”);
}
}
}

我能感同身受,因为我已经为此奋斗了一段时间。 我实现了,它改进了Java1.6中PermGen的生存期,但没有消除核心问题

出于某种原因,我没有看到Java8中的问题,所以我放弃了尝试解决这个问题。(尚未尝试使用Java 7)


希望你能比我走得更远。

哇。举起我只是快速地打了一枪,似乎效果很好。但是,不直接使用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);
    }           
}      
公共静态无效测试(){
对于(int i=0;i<10000000;i++){
GroovyShell gs=新GroovyShell();
Script=gs.parse(“'Hello,World';”);
对象结果=script.run();
断言result.equals(“你好,世界”);
clearAllClassInfo(script.getClass());
}                  
}
公共静态无效clearAllClassInfo(类类型){
试一试{
字段globalClassValue=ClassInfo.class.getDeclaredField(“globalClassValue”);
globalClassValue.setAccessible(true);
GroovyClassValue classValueBean=(GroovyClassValue)globalClassValue.get(null);
classValueBean.remove(类型);
}捕获(例外情况除外){
抛出新的运行时异常(ex);
}           
}      
显然,您可以对清洁器进行一些优化,以消除大量反射

PermGen相当平坦:

课程正在以轻快的速度进行:


要归功于@。

不幸的是,这种方法的结果与我的示例完全相同。谢谢@Nicholas!我用Java6和Java7对此进行了测试,并在两个版本(以及多线程场景)中卸载了这些类。尽管如此,我还是会在Groovy Jira上提出一个缺陷,因为我认为这应该由Groovy本身而不是由它的用户来处理。
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);
    }           
}