2010-07-26 24 views
168

No puedo encontrar una definición de lo que hace la marca Java VM CMSClassUnloadingEnabled, aparte de algunas definiciones muy confusas de alto nivel como "se deshace de sus problemas PermGen" (which it doesn't, btw).¿Qué hace JVM marcar CMSClassUnloadingEnabled en realidad?

He buscado en el sitio de Sun/Oracle, e incluso the options list en realidad no dice lo que hace.

Según el nombre de la bandera, supongo que CMS Garbage Collector no descarga las clases de forma predeterminada, y este indicador lo enciende, pero no estoy seguro.

Respuesta

201

actualización Esta respuesta es relevante para Java 5-7, Java 8 tiene esto esté arreglado: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos van a mt.uulu

Para Java 5-7:

El estándar de Oracle/Sun VM verá en el mundo es: las clases son para siempre. Una vez cargados, permanecen en la memoria incluso si a nadie le importa más. Esto usualmente no es un problema ya que no tienes tantas clases de "configuración" pura (= se usa una vez para la configuración y luego nunca más). Entonces, incluso si toman 1 MB, a quién le importa.

Pero últimamente, tenemos idiomas como Groovy, que definen las clases en tiempo de ejecución. Cada vez que ejecuta un script, se crean una (o más) clases nuevas y permanecen en PermGen para siempre. Si está ejecutando un servidor, eso significa que tiene una pérdida de memoria.

Si habilita CMSClassUnloadingEnabled, el GC barrirá PermGen también y eliminará las clases que ya no se utilizan.

[EDIT] También tendrá que activar UseConcMarkSweepGC (gracias a Sam Hasler). Ver esta respuesta: https://stackoverflow.com/a/3720052/2541

+15

Según http://stackoverflow.com/a/3720052/2541 para 'CMSClassUnloadingEnabled' tener cualquier impacto, 'UseConcMarkSweepGC' también debe establecerse –

+1

No estoy seguro de cómo esto afecta la idea de usar UseConcatSweepGC, pero parece que recientemente se corrigió un error en CMSClassUnloadingEnabled. Se indica como corregido aquí: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325 – BillR

+0

Para idiomas como Groovy que definen dinámicamente las clases, ¿es una buena práctica habilitar esta bandera para limpiar periódicamente PermGen? –

34

Según la publicación de blog The most complete list of -XX options for Java JVM, determina si la descarga de clase está habilitada en el recolector de elementos no utilizados de CMS. El valor predeterminado es false. Hay otra opción llamada ClassUnloading que es true por defecto que (presumiblemente) afecta a los demás recolectores de basura.

La idea es que si el GC detecta que una clase previamente cargada ya no se usa en ninguna parte de la JVM, puede reclamar la memoria utilizada para contener el código de byte y/o código nativo de la clase.

Ajuste CMSClassUnloadingEnabled podría ayudarle con su problema PermGen si este momento está usando el colector CMS. Pero lo más probable es que no esté utilizando el CMS, o que tenga una pérdida de memoria relacionada con un cargador de clases genuino. En este último caso, su clase nunca aparecerá ante el GC para que no se use ... y por lo tanto nunca será descargada.


Aaron Digulla dice "las clases son para siempre". Esto no es estrictamente cierto, incluso en el mundo puramente Java. De hecho, la duración de una clase está ligada a su cargador de clases. Por lo tanto, si puede organizar que un cargador de clases sea basura (y eso no siempre es fácil de hacer), las clases que cargó también serán basura.

De hecho, esto es lo que ocurre cuando se realiza una nueva implementación de una aplicación web. (O al menos, eso es lo que debería suceder, si puede evitar los problemas que conducen a una fuga de almacenamiento de permgen).)

22

Un ejemplo donde esto es útil:

Configuración -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled en nuestra JVM Weblogic 10.3 ayudaron a resolver un problema donde la aplicación JAX-WS creó una nueva clase de proxy para cada llamada de servicio web, que finalmente llevan a cabo de la memoria errores

No fue trivial rastrear. El siguiente código devuelve siempre la misma clase proxy para port

final MyPortType port = 
Service.create(
     getClass().getResource("/path/to.wsdl"), 
     new QName("http://www.example.com", "MyService")) 
    .getPort(
     new QName("http://www.example.com", "MyPortType"), 
     MyPortType.class); 

Internamente, este proxy delegado a una instancia de weblogic.wsee.jaxws.spi.ClientInstance, que a su vez delega a una nueva clase $Proxy[nnnn] donde n se incrementa en cada llamada. Al agregar los indicadores, n aún se incrementó, pero al menos esas clases temporales se eliminaron de la memoria.

En un plano más general, esto puede ser muy útil para hacer un uso intensivo de la reflexión y proxies Java a través java.lang.reflect.Proxy

+0

+1 para compartir experiencia real. También tuvimos este problema en el cuadro de torsión donde el servidor generó una gran cantidad de clases debido a los procesos de compilación JRuby. – nurettin

+7

también tenga en cuenta que '-XX: + CMSPermGenSweepingEnabled' está en desuso en favor de' -XX: + CMSClassUnloadingEnabled' – nurettin

+0

@nurettin: Es bueno saberlo, gracias por la información –

Cuestiones relacionadas