2011-11-05 2 views
9

GC 수집을 위해 메모리 수집기와 함께 CMS 수집기를 사용하는 Tomcat 응용 프로그램에서 작업합니다. 웹 애플리케이션을 다시로드하면 Old gen이 GC를 실행하기에 충분하지만 죽은 Classloader가 수집되지 않는 경우 가끔 있습니다.perm 파생물은 언제 수집됩니까?

필자는 클래스가 perm gen에 할당되고 Old gen 컬렉션에서 무시되고 있다고 추측했다. 이 이론을 테스트하기 위해 다음 테스트 클래스를 작성했습니다.

package test; 

import java.io.IOException; 
import java.io.InputStream; 

import org.apache.commons.io.IOUtils; 

/* 
JVM Options: 
-server -XX:+UseMembar -XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly -Xms100m -Xmx100m 
-XX:PermSize=100m -XX:NewSize=10m -XX:MaxNewSize=10m 
-verbose:gc -Xloggc:gc.log -XX:+PrintGCTimeStamps 
-XX:+PrintGCDetails 
*/ 
public class ClassLoaderTest extends ClassLoader 
{ 
    @Override 
    protected synchronized Class<?> loadClass(String xiName, boolean xiResolve) 
     throws ClassNotFoundException 
    { 
    if (xiName.equals("test")) 
    { 
     // When asked to load "test", load Example.class 
     Class<?> c = Example.class; 
     String className = c.getName(); 
     String classAsPath = className.replace('.', '/') + ".class"; 
     InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); 
     byte[] classData = null; 
     try 
     { 
     classData = IOUtils.toByteArray(stream); 
     } 
     catch (IOException e) 
     { 
     e.printStackTrace(); 
     } 
     return defineClass(className, classData, 0, classData.length); 
    } 
    return super.loadClass(xiName, xiResolve); 
    } 

    public static class Example {} 
    public static ClassLoaderTest classLoaderTest; 

    public static void main(String[] args) throws Exception 
    { 
    // Allocate CL in new gen 
    classLoaderTest = new ClassLoaderTest(); 

    // Load a class - allocated in perm gen 
    classLoaderTest.loadClass("test"); 

    // Discard CL 
    classLoaderTest = null; 

    // Pause at end 
    Thread.sleep(99 * 60 * 1000); 
    } 

    public final byte[] mMem = new byte[85 * 1024 * 1024]; 
} 

나는이 클래스를 실행하고 VisualVM과를 사용하여 출력을 모니터링하고이 수집 죽은 클래스 로더없이 일어나는 여러 구약과 젊은 세대 컬렉션이 실제로 있었다 때문에 큰 바이트 배열이 메모리에 남아 있음을 보았다.

VisualVM Visual GC

무엇 파마 세대를 트리거 할 수집 할?

+0

[Perm ...]가 [... 맞습니까?] (http://en.wiktionary.org/wiki/permanent#Adjective) –

+4

Java Perm Gen에 할당 된 메모리는 여전히 수집 될 수 있습니다. JVM은 Perm Gen을 사용하여 매우 드물게 해제 될 것으로 예상되는 데이터를 보유합니다. – mchr

답변

4

"CMSPermGenSweepingEnabled"및 "CMSClassUnloadingEnabled"JVM 옵션을 확인하십시오. (그물에 대한 논의는 많습니다.) 특히, 첫 번째는 PermGen을 가비지 수집 실행에 포함한다고 가정합니다. 기본적으로 PermGen 공간은 가비지 수집에 포함되지 않습니다 (따라서 경계없이 증가합니다).

+1

경계가 없으면 성장하지 않고 매우 명확한 상한선이 있습니다. 그렇기 때문에 종종 두려운 클래스 로더 누수가 발생합니다. https://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java –

+0

@Cameron Skinner + Point taken! 그것은 MaxPermSize에 상관없이 성장할 _attempts_ : – mazaneicha

+1

-XX : + CMSPermGenSweepingEnabled -XX : + CMSClassUnloadingEnabled를 JVM args에 추가하려고 시도했습니다. 나는 오직 -XX : + CMSClassUnloadingEnabled가 실제로 아무것도하지 않는다는 것을 발견했다. 나는 또한 perm gen이 두 번째 젊은 세대 컬렉션 직후 2 분 후에 수집되었다는 사실에 놀랐다. – mchr

관련 문제