¿Qué hace JVM marcar CMSClassUnloadingEnabled en realidad?

No puedo encontrar una definición de lo que hace la CMSClassUnloadingEnabled Java VM CMSClassUnloadingEnabled , aparte de algunas definiciones muy confusas de alto nivel como “se deshace de tus problemas PermGen” (lo que no ocurre , por cierto).

He buscado en el sitio de Sun / Oracle, e incluso la lista de opciones en realidad no dice lo que hace.

Basado en el nombre de la bandera, supongo que CMS Garbage Collector no descarga las clases de forma predeterminada, y esta bandera lo enciende, pero no estoy seguro.

Actualización Esta respuesta es relevante para Java 5-7, Java 8 lo ha solucionado: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos go to mt. uulu

Para Java 5-7:

La apariencia estándar de Oracle / Sun VM 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 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 barrerá también PermGen y eliminará las clases que ya no se utilizan.

[EDITAR] También deberá habilitar UseConcMarkSweepGC (gracias a Sam Hasler ). Ver esta respuesta: https://stackoverflow.com/a/3720052/2541

Según la publicación del blog La lista más completa de opciones de -XX para Java JVM , determina si la descarga de clases 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, lo 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 bytecode y / o código nativo de la clase.

Establecer CMSClassUnloadingEnabled podría ayudar con su problema de permgen si actualmente está utilizando el recostackdor de 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 sucede cuando realizas una redistribución en caliente 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).

Un ejemplo donde esto es útil:

Configuración -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled en nuestro Weblogic 10.3 JVM ayudó a resolver un problema donde la implementación de JAX-WS creó una nueva clase de proxy para cada llamada de servicio web, lo que finalmente generó errores de memoria.

No fue trivial rastrear. El siguiente código siempre devolvió la misma clase de proxy para el 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 se delegó en una instancia de weblogic.wsee.jaxws.spi.ClientInstance , que de nuevo delegó en una nueva clase $Proxy[nnnn] donde n se incrementó en cada llamada. Al agregar las banderas, n aún se incrementaba, pero al menos esas clases temporales se eliminaron de la memoria.

En una nota más general, esto puede ser muy útil cuando se hace un uso intensivo de la reflexión y los proxies de Java a través de java.lang.reflect.Proxy