Java 反复使用Groovy外壳会导致PermGen空间被填满
在应用程序中,我反复创建GroovyShell实例并在其上执行自定义脚本。在执行此操作时,我遇到了一些问题,Java 6和Java 7中的perm gen空间被填满,而类没有被卸载。我正在使用Groovy 2.4.7。可使用以下代码再现此问题: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
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);
}
}