Despliegue de Spring Boot en Tomcat: fuga de permgen debido al registro de actividades.
Me encontré con un problema de fuga de memoria al redeployar una aplicación de spring boot 2.5
en tomcat 9
.
Proceso de depuración:
- Ejecución de startup.bat de Tomcat
- Implementación de war
- Recarga/desimplementación de war
- Ejecución de Tomcat para encontrar fugas
- Comprobar las clases cargadas en visual vm
Tomcat findleaks informa de una fuga y visual VM indica que las clases no se descargan.
Próximos pasos:
- Tomar un heapdump
- Cargar el volcado en el analizador de memoria de Eclipse
- Listar objetos con referencias entrantes y filtrar a org.apache.catalina.loader.ParallelWebappClassLoader
Esto también lista los cargadores de clase con un estado DESTROYED
. Para un cargador de clase destruido, haga lo siguiente:
- Ruta a las raíces de GC > Excluir todas las referencias de fantasmas/débiles/suaves/etc.
Esto indica que aún puede haber una referencia fuerte relacionada con org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean
.
Intenté recrear el problema en un proyecto simple de spring boot
utilizando el registro de logback y log4j2. Ambos muestran el mismo escenario pero con una causa diferente (enganches de apagado).
La depuración y el código basado en el iniciador de spring boot
se pueden encontrar aquí: https://github.com/webbres/spring-boot-permgen-issue/tree/master/debugging
En esta etapa, no estoy seguro si la fuga de permgen en mi aplicación real está relacionada con la del repositorio vinculado.
¿Hay medidas adicionales que deban tomarse que spring boot no esté manejando en relación con el uso de los marcos de registro en un war? He intentado agregar org.apache.logging.log4j:log4j-web
como una dependencia, pero esto no parece resolver el problema del gancho de apagado en el proyecto de demostración.
Siento que estoy perdiendo algo…
Agregando -Dlog4j2.disable.jmx=true
al CATALINA_OPTS y logging.register-shutdown-hook=false
al application.properties
, ya no veo referencias al filtrar las referencias de fantasmas/débiles/suaves/etc. Sin embargo, todavía veo la instancia DESTROYED del ParallelWebappClassLoader
y las clases no están siendo descargadas.
davy.ai
Depurando un problema de pérdida de memoria con Spring Boot y Tomcat
Descripción del problema
Como experto de IT especializado en Spring Boot, Tomcat, Log4j y Log4j2, me encontré con un problema de pérdida de memoria al volver a implementar una aplicación “spring boot 2.5” en “tomcat 9”. Al recargar o anular la implementación del archivo WAR, el informe “findleaks” de Tomcat reporta una fuga y Visual VM indica que las clases no se descargan.
Proceso de depuración
Para depurar este problema, seguí el siguiente proceso:
startup.bat
Pasos siguientes
Después de comprobar las fugas y las clases cargadas, realicé un heapdump y lo cargué en Eclipse Memory Analyzer. Luego, listé los objetos con referencias entrantes y filtré la clase
org.apache.catalina.loader.ParallelWebappClassLoader
. Esto también listó los cargadores de clase con un estadoDESTROYED
. Para un cargador de clase destruido, seguí estos pasos:Esto indicó que todavía podría haber una referencia fuerte relacionada con
org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean
.Intenté recrear el problema en un proyecto Spring Boot simple utilizando el registro de Logback y Log4j2. Ambos mostraron el mismo escenario, pero con una causa diferente (hooks de apagado).
La depuración y el código basado en el iniciador de Spring Boot se pueden encontrar aquí: https://github.com/webbres/spring-boot-permgen-issue/tree/master/debugging
En este momento, no estoy seguro si la fuga de Permgen en mi aplicación real está relacionada con la del repositorio vinculado.
Pasos adicionales
También estoy seguro si hay pasos adicionales que se deben realizar que el iniciador de Spring Boot no está manejando con respecto al uso de los marcos de registro en un archivo WAR. He intentado agregar
org.apache.logging.log4j: log4j-web
como una dependencia, pero esto no parece resolver el problema de los hooks de apagado en el proyecto de demostración.Agregar
-Dlog4j2.disable.jmx=true
en losCATALINA_OPTS
ylogging.register-shutdown-hook=false
en losapplication.properties
resulta en no obtener más referencias al filtrar todas las referencias fantasma/débiles/suaves/etc. Sin embargo, todavía veo la instanciaDESTROYED
deParallelWebappClassLoader
y las clases no se descargan.Conclusión
En general, sospecho que el problema de la fuga de memoria está relacionado con el uso de Log4j o Log4j2 con Tomcat y Spring Boot. Se requiere más depuración para identificar la causa raíz y encontrar una solución.