2011-11-05 38 views
9

我在使用CMS收集器和內存條觸發GC的Tomcat應用程序上工作。當我重新加載webapps時,有時最終會出現這樣一種情況,即Old gen足以觸發GC,但死亡的Classloaders不會被收集。何時收集燙髮?

我讀過,類被分配到電燙,並猜測他們因此被舊集合忽略。我寫了下面的測試課來測試這個理論。

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

檢出JVM選項「CMSPermGenSweepingEnabled」和「CMSClassUnloadingEnabled」。 (關於網絡的使用有很多討論)。特別是,第一個假設將PermGen包含在垃圾收集運行中。默認情況下,PermGen空間永遠不會包含在垃圾回收中(因此無限制地增長)。

+1

它不會無邊界增長,有一個非常明確的上限。這就是爲什麼你經常得到可怕的類加載器泄漏:https://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java –

+0

@Cameron Skinner + Point taken!它_attempts_增長,不考慮MaxPermSize :-) – mazaneicha

+1

我嘗試添加-XX:+ CMSPermGenSweepingEnabled -XX:+ CMSClassUnloadingEnabled到我的JVM參數。我發現只有-XX:+ CMSClassUnloadingEnabled實際上做了任何事情。我還驚訝地發現,第二代青年收集後不久,2分鐘後才收集燙髮。 – mchr