2017-01-04 28 views
2

在應用程序中,我一再創造GroovyShell的實例,對它們執行自定義腳本。這樣做時,我遇到了Java 6和Java 7中的perm gen空間被填滿並且類不會被卸載的問題。我正在使用Groovy 2.4.7。重複使用Groovy的炮彈導致PermGen的空間充滿

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不起作用。

有沒有辦法在這裏強制卸載類或者使得類是從PermGen的空間刪除觸發GC?

回答

1

哇。耽誤。我剛剛給了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的很平: enter image description here

和類以輕快的步伐正在卸載: enter image description here

感謝@BilboDai

+0

謝謝@尼古拉斯!我用Java 6和7測試了這個,並且這兩個類都卸載了兩個變體版本(並且也在多線程場景中)。不過,我會在Groovy Jira上提出一個缺陷,因爲在我看來,這應該由Groovy本身來處理,而不是由其用戶來處理。 –

0

重用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"); 
     } 
    } 
} 
+0

不幸的是,這種做法的結果是完全相同的行爲作爲我的榜樣。 –

2

我能感同身受,因爲我一直在這個搏鬥了一會兒。 我實現了this solution,它改進了Java 1.6中PermGen的生命週期,但並未消除核心問題。

出於某種原因,我沒有看到這個問題在Java中8,所以我放棄了試圖解決。 (還沒有用Java 7試過)。

希望你可以做得比我做到了。