2017-01-04 9 views
2

응용 프로그램에서 GroovyShell의 인스턴스를 반복적으로 작성하고 사용자 정의 스크립트를 실행합니다. 이 작업을 수행 할 때 Java 6 및 Java 7의 perm gen 공간이 채워지고 클래스가 언로드되지 않는 문제가 발생합니다. Groovy 2.4.7을 사용하고 있습니다. 나는 다음과 같은 VM 인수를 사용하고Groovy Shell을 반복적으로 사용하면 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"); 
     } 
    } 
} 

:이 문제는 다음 코드를 재현 할 수

-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을줬고 완벽하게 작동하는 것 같습니다. 하지만 셸을 직접 사용하는 대신 스크립트를 컴파일 한 다음 동일한 결과에 대해 스크립트를 실행합니다. 그런 다음 지정된 클리너를 호출하십시오.

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

그리고 클래스가 활발한 속도로 언로드되고있다 : @BilboDaienter image description here

신용.

+0

감사합니다. @Nicholas! 필자는 Java 6 및 7에서이를 테스트했으며 클래스는 두 변형 버전을 언로드했습니다 (다중 스레드 시나리오에서도). 그래도 Groovy Jira에 결함을 제기 할 것입니다. 제 의견으로는 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에서 문제가 보이지 않기 때문에 해결을 포기했습니다. (자바 7로 시도하지 않았다).

바라건대 내가 한 것보다 더 많이 얻을 수 있기를 바랍니다.