¿Qué hace realmente la bandera JVM CMSClassUnloadingEnabled?
183
Por mi vida, no puedo encontrar una definición de lo que CMSClassUnloadingEnabledrealmente hace el indicador Java VM , aparte de algunas definiciones de alto nivel muy difusas como "deshacerse de sus problemas de PermGen" ( que no es , por cierto).
He buscado en el sitio de Sun / Oracle, e incluso la lista de opciones en realidad no dice lo que hace.
Según el nombre de la bandera, supongo que el recolector de basura CMS no descarga las clases de manera predeterminada, y esta bandera lo enciende, pero no puedo estar seguro.
El aspecto estándar de Oracle / Sun VM en el mundo es: Las clases son para siempre. Entonces, una vez cargados, permanecen en la memoria incluso si a nadie le importa más. Esto generalmente no es un problema ya que no tiene tantas clases puramente de "configuración" (= usado una vez para la configuración y luego nunca más). Entonces, incluso si ocupan 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) nuevas clases y permanecen en PermGen para siempre. Si está ejecutando un servidor, eso significa que tiene una pérdida de memoria.
Si habilita CMSClassUnloadingEnabledel GC, también barrerá PermGen y eliminará las clases que ya no se usan.
De acuerdo con stackoverflow.com/a/3720052/2541 para CMSClassUnloadingEnabledtener algún impacto, UseConcMarkSweepGCtambién se debe configurar
Sam Hasler
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 comenta
Bill Rosmus
3
@ Kevin: Sí, definitivamente. Vea al final de groovy.codehaus.org/Running : "Groovy crea clases dinámicamente, pero la máquina virtual Java predeterminada no GC el PermGen. Si está utilizando Java 6 o posterior, se necesita agregar -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCPara habilitar CMSClassUnloadingEnabled".
De acuerdo con la publicación del blog La lista más completa de opciones -XX para Java JVM , determina si la descarga de clases está habilitada bajo el recolector de basura CMS. El valor por defecto es false. Hay otra opción llamada ClassUnloadingque es truepor defecto que (presumiblemente) afecta a los otros recolectores de basura.
La idea es que si el GC detecta que una clase cargada previamente ya no se usa en ninguna parte de la JVM, puede recuperar la memoria utilizada para contener el bytecode de las clases y / o el código nativo.
Configurar CMSClassUnloadingEnabled podría ayudarlo con su problema de permgen si actualmente está utilizando el recopilador de CMS . Pero lo más probable es que no esté utilizando el CMS o que tenga una pérdida de memoria genuina relacionada con el cargador de clases. En el último caso, su clase nunca aparecerá en el GC como no utilizada ... y, por lo tanto, nunca se descargará.
Aaron Digulla dice "las clases son para siempre". Esto no es estrictamente cierto, incluso en el mundo puramente Java. De hecho, la vida útil de una clase está vinculada a su cargador de clases. Entonces, si puede organizar que un cargador de clases sea basura recolectada (y eso no siempre es algo fácil de hacer), las clases que cargó también serán recolectadas.
De hecho, esto es lo que sucede cuando realizas 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).
La configuración -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledde nuestra JVM de Weblogic 10.3 ayudó a resolver un problema en el que la implementación JAX-WS creó una nueva clase de proxy para cada llamada al servicio web, lo que eventualmente condujo a errores de memoria insuficiente.
No fue trivial rastrear. El siguiente código siempre devolvió la misma clase de proxy paraport
finalMyPortType port =Service.create(
getClass().getResource("/path/to.wsdl"),newQName("http://www.example.com","MyService")).getPort(newQName("http://www.example.com","MyPortType"),MyPortType.class);
Internamente, este proxy delega en una instancia de weblogic.wsee.jaxws.spi.ClientInstance, que nuevamente delega en una nueva $Proxy[nnnn]clase donde nse incrementa en cada llamada. Al agregar las banderas, ntodavía se incrementó, 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
+1 para compartir experiencias reales. También tuvimos este problema en torquebox donde el servidor generó una gran cantidad de clases debido a los procesos de compilación de JRuby.
nurettin
77
También tenga en cuenta que -XX:+CMSPermGenSweepingEnabledestá en desuso a favor de-XX:+CMSClassUnloadingEnabled
nurettin
3
Sin embargo, una solución real para este problema es crear el puerto una vez y reutilizarlo. Así es como se supone que se debe usar JAX-WS. El puerto también es 100% seguro para subprocesos.
rustyx
@rustyx: ¿Puedes respaldar esa afirmación con algún enlace autorizado? Siempre he sido muy cauteloso con la reutilización de proxies y stubs de servicios web ... Por ejemplo, vea los descargos de responsabilidad de Apache CXF . O esta pregunta
Lukas Eder
1
@rukavitsya: Como dije en mi respuesta. Cada vez que llamé a la lógica anterior, se creó un nuevo proxy
CMSClassUnloadingEnabled
tener algún impacto,UseConcMarkSweepGC
también se debe configurar-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC
.UseConcMarkSweepGC
Para habilitarCMSClassUnloadingEnabled
".De acuerdo con la publicación del blog La lista más completa de opciones -XX para Java JVM , determina si la descarga de clases está habilitada bajo el recolector de basura CMS. El valor por defecto es
false
. Hay otra opción llamadaClassUnloading
que estrue
por defecto que (presumiblemente) afecta a los otros recolectores de basura.La idea es que si el GC detecta que una clase cargada previamente ya no se usa en ninguna parte de la JVM, puede recuperar la memoria utilizada para contener el bytecode de las clases y / o el código nativo.
Configurar CMSClassUnloadingEnabled podría ayudarlo con su problema de permgen si actualmente está utilizando el recopilador de CMS . Pero lo más probable es que no esté utilizando el CMS o que tenga una pérdida de memoria genuina relacionada con el cargador de clases. En el último caso, su clase nunca aparecerá en el GC como no utilizada ... y, por lo tanto, nunca se descargará.
Aaron Digulla dice "las clases son para siempre". Esto no es estrictamente cierto, incluso en el mundo puramente Java. De hecho, la vida útil de una clase está vinculada a su cargador de clases. Entonces, si puede organizar que un cargador de clases sea basura recolectada (y eso no siempre es algo fácil de hacer), las clases que cargó también serán recolectadas.
De hecho, esto es lo que sucede cuando realizas 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).
fuente
Un ejemplo donde esto es útil:
La configuración
-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
de nuestra JVM de Weblogic 10.3 ayudó a resolver un problema en el que la implementación JAX-WS creó una nueva clase de proxy para cada llamada al servicio web, lo que eventualmente condujo a errores de memoria insuficiente.No fue trivial rastrear. El siguiente código siempre devolvió la misma clase de proxy para
port
Internamente, este proxy delega en una instancia de
weblogic.wsee.jaxws.spi.ClientInstance
, que nuevamente delega en una nueva$Proxy[nnnn]
clase donden
se incrementa en cada llamada. Al agregar las banderas,n
todavía se incrementó, 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
fuente
-XX:+CMSPermGenSweepingEnabled
está en desuso a favor de-XX:+CMSClassUnloadingEnabled