2011-11-05 15 views
9

Lavoro su un'applicazione Tomcat che utilizza il raccoglitore CMS insieme a una barra di memoria per attivare GC. Quando ricarico webapps, a volte finisco in una situazione in cui il vecchio gen è abbastanza pieno da innescare GC ma i Classloader morti non vengono raccolti.Quando viene raccolta la perm gen?

Ho letto che le classi sono allocate nel perm gen e ho intuito che venivano quindi ignorate dalle raccolte di vecchie generazioni. Ho scritto la seguente classe di test per testare questa teoria.

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]; 
} 

mi sono imbattuto questa classe e monitorare l'output utilizzando VisualVM e ho visto che ci sono stati effettivamente più vecchi e giovani generazione collezioni che accadono senza il programma di caricamento classi morti essere raccolti e quindi il grande array di byte rimasti in memoria.

VisualVM Visual GC

Cosa farebbe scattare l'Perm Gen da raccogliere?

+0

Sai cos'è "Perm" è l'abbreviazione di [... giusto?] (Http://en.wiktionary.org/wiki/permanent#Adjective) –

+4

La memoria allocata in Java Perm Gen può essere ancora raccolta. La JVM usa Perm Gen per conservare i dati che si aspetta siano liberati molto raramente. – mchr

risposta

4

Controllare le opzioni JVM "CMSPermGenSweepingEnabled" e "CMSClassUnloadingEnabled". (Ci sono molte discussioni sulla rete per il loro uso.) In particolare, il primo suppone di includere PermGen in una raccolta di dati inutili. Per impostazione predefinita, lo spazio PermGen non viene mai incluso nella garbage collection (e quindi cresce senza limiti).

+1

Non cresce senza limiti, c'è un limite superiore ben definito. Ecco perché ottieni spesso la temuta fuga di classloader: https://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java –

+0

@Cameron Skinner + Punto preso! _ttempts_ per crescere senza riguardo a MaxPermSize :-) – mazaneicha

+1

Ho provato ad aggiungere il -XX: + CMSPermGenSweepingEnabled -XX: + CMSClassUnloadingEnabled ai miei argomenti JVM. Ho scoperto che solo -XX: + CMSClassUnloadingEnabled ha effettivamente fatto qualcosa. Sono stato anche sorpreso di scoprire che il perm gen è stato raccolto solo dopo 2 minuti poco dopo la seconda raccolta di giovani gen. – mchr

Problemi correlati