2014-12-12 2 views
2

n 프로세스마다 n 분마다 스크립트를 실행하는 Java 7 프로젝트가 있습니다. 다음은 스크립트를 실행하는 코드 예제입니다. 그루비 몇 가지 이유로 Groovy 업데이트로 인해 PermGen에 죽은 GroovyClassLoaders가 발생했습니다

ScheduledFuture scheduledFuture = scheduledService.scheduleAtFixedRate(new Runnable() { 
      @Override 
      public void run() { 
       try (GroovyClassLoader cl = new GroovyClassLoader()) { 
        // Load up reusable script modules in the class loader 
        Class scriptClass = cl.parseClass(scriptSource); 
        Foo script = optimizationClass.newInstance(); 

        // Tell Groovy that we don't need class meta info 
        GroovySystem.getMetaClassRegistry().removeMetaClass(scriptClass); 
        script.run(); 
        cl.clearCache(); 
       } catch (IOException e) { 
        LOGGER.error("Failed to cleanup Groovy class loader, this will cause a memory leak", e); 
       } 
      } 
     }, 0, scheduledRun, TimeUnit.SECONDS); 

     scheduledFuture.get(); 

은 2.3.8 또는 그루비 2.2.0가, 파마 세대가 죽은 그루비 클래스 로더 가득지고 계속 그루비로 업그레이드 파마 창에는 메모리 누수가 없다 2.1.7.

0x000000071ada2cd0 33 488160 0x000000071b2493c8 dead groovy/lang/[email protected] 0x00000007265883b8 33 488160 0x0000000725837270 dead groovy/lang/[email protected] 0x00000007157b5da0 26 370736 0x000000072326f468 live org/codehaus/groovy/runtime/callsite/[email protected] 0x000000071ada1fb0 32 423944 0x000000071af03a98 dead groovy/lang/[email protected] 0x0000000719d605b0 32 456520 0x000000071af04798 dead groovy/lang/[email protected] 0x0000000725b82500 0 0 0x000000072326f468 dead groovy/lang/[email protected] 0x00000007263eef80 34 532448 0x0000000726d5c678 dead groovy/lang/[email protected] 0x000000072687b3c8 33 485288 0x0000000726c36340 dead groovy/lang/[email protected] 0x0000000725d56db0 33 485288 0x000000072607bcc0 dead groovy/lang/[email protected]

Full GC가 발생할 때까지 기다렸지 만 Groovy 2.2 이후의 모든 버전이 Perm Gen을 채우고있는 것으로 보입니다. 내가 업데이트 된 버전까지 있던 버전 사이의 릴리스 정보를 확인한 결과,이 변경 사항을 알리는 변경 사항을 발견하지 못했습니다.

여기에 비슷한 문제가 있는지 확인하고 몇 가지 제안을 시도했지만 운이 없었습니다. 원인에 대한 아이디어가 있습니까?

업데이트 :
GroovyClassLoader의 GrepCode에서 Diff를 2.1.7에서 2.2.0으로 변경했는데 변경 사항이 없습니다. 또한 응용 프로그램이 실행 중일 때 힙 덤프 파일을 가져 왔으며 강력한 참조를 위해 GC 루트에 대한 경로가 없었습니다. 내가 스크립트를 컴파일하지만 실행하지 않는 경우 내가 파마 창에서 0 그루비 클래스 로더를 가지고 스크립트를 컴파일하지 않는 경우

Class scriptClass = cl.parseClass(scriptSource); 
Foo script = scriptClass.newInstance(); 

, 내가 얻을 :

문제는 주변 것으로 보인다 죽은 그루비 클래스 로더.

업데이트 :
누수의 원인이되는 코드를 찾았습니다.

Foo script = scriptClass.newInstance(); 

스크립트를 실행하려면 새 인스턴스를 만들어야하므로이를 수정하는 방법을 잘 모릅니다.

+0

Java 8이 PermGen 문제를 제거하지 않았습니까? :) (실제로 이것이 왜 일어날 지에 대해서도 관심이 있습니다!) –

+0

Java 8은 PermGen 공간을 Metaspace로 바꿨습니다.이 공간은 기본적으로 자동으로 확장됩니다. 그러나 Java 8은 실제 누수에 대해서는 아무 것도하지 않습니다. 여전히 OutOfMemoryError : Metaspace를 얻을 수 있습니다. 이유 및 방법을 읽고 싶다면 주제에 관한 블로그 시리즈를 확인하십시오. http://java.jiderhamn.se/2011/12/11/classloader-leaks-i-how -to-find-classloader-leaks-with-eclipse-memory-analyzer-mat/ –

+0

현재 Java 8 로의 업그레이드는 현재로서는 실행 가능한 솔루션이 아닙니다.또한 Groovy를 업그레이드하면이 누수가 발생하는 이유는 해결되지 않습니다. – ColinMc

답변

0

Groovy로 작성된 파일 파서와 비슷한 문제가 발생했습니다. 많은 문자열 조작을 할 때 - 메모리 누수가 발생했습니다. 클래스 로더에서 clearCache()를 시도하고 사용하지 않고 .removeMetaClass()를 시도했습니다.

마지막으로 groovy 모듈을 jar 파일로 컴파일하고 프로젝트에 포함하여이 문제를 해결했습니다.

+0

슬프게도 Groovy cod가 필요하기 때문에이 옵션을 사용할 수 없습니다. 응용 프로그램 외부에 있어야합니다. Groovy 코드를 데이터베이스에 저장하고 응용 프로그램이이를 실행합니다. 이는 엔지니어가 즉시 코드를 재배포 할 수 있도록 해줍니다. – ColinMc

4

Groovy 스크립트를 컴파일하고 실행하는 데 동일한 문제가있었습니다. 나는 마지막으로이 방법을 운동 : 1. 당신은 7에서 자바 버전으로 작업하는 경우, 그렇지 않으면 당신은 운이

public static void clearAllClassInfo(Class<?> type) throws Exception { 
    Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue"); 
    globalClassValue.setAccessible(true); 
    GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null); 
    classValueBean.remove(type); 
} 

2.

를 컴파일 한 후 클래스를 청소하려면 아래 코드를 사용할 수 있습니다, 당신은 단지 필요하기 때문에 SystemProperties에 속성을 추가하십시오.

-Dgroovy.use.classvalue=true 
+0

내가 누출 된 누수에 대한 해결책을 찾고 있었고 정적 MetaClassRegistry에 관한 모든 것을 찾을 수있었습니다. 그러나 그것은 문제가 아니었다. 나는 그 방안들을 넣었고 누출은 사라졌습니다. Groovy에서 런타임 컴파일러로 사용될 때 많은 메모리 누수가있는 것처럼 보입니다. 고마워요! – caeus