Pérdida de memoria al volver a implementar la aplicación en Tomcat

Cuando vuelvo a implementar mi aplicación en tomcat, aparece el siguiente problema:

The web application [] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@10d16b]) and a value of type [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty] (value [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty@1a183d2]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak. 

Además, estoy usando ehcache en mi aplicación. Esto también parece dar como resultado la siguiente excepción.

  SEVERE: The web application [] created a ThreadLocal with key of type [null] (value [com.sun.xml.bind.v2.ClassFactory$1@24cdc7]) and a value of type [java .util.WeakHashMap... 

El ehcache parece crear un mapa hash débil y recibo el mensaje de que es muy probable que cree una pérdida de memoria.

Busqué en la red y encontré esto, http://jira.pentaho.com/browse/PRD-3616 pero no tengo acceso al servidor como tal.

Por favor, avíseme si estas advertencias tienen algún impacto funcional o pueden ser ignoradas. Usé la opción “Buscar pérdida de memoria” en el administrador de tomcat y dice “No se encontraron pérdidas de memoria”

Cuando vuelve a implementar su aplicación, Tomcat crea un nuevo cargador de clases. El cargador de clase anterior debe ser basura, de lo contrario se obtiene una pérdida de memoria permgen.

Tomcat no puede verificar si la recolección de basura funcionará o no, pero conoce varios puntos comunes de fallas. Si el cargador de la clase ThreadLocal establece un ThreadLocal con una instancia cuya clase fue cargada por el cargador de la clase webapp en sí, el hilo del servlet guarda una referencia a esa instancia. Esto significa que el cargador de clases no será basura.

Tomcat realiza varias de estas detecciones, consulte aquí para obtener más información . Limpiar locals de hilo es difícil, tendrías que llamar a remove() en el ThreadLocal en cada uno de los hilos a los que se ha accedido. En la práctica, esto solo es importante durante el desarrollo cuando vuelves a implementar tu aplicación web varias veces. En producción, probablemente no se vuelva a desplegar, por lo que puede ignorarse.

Para averiguar realmente qué instancias definen los locales del hilo, debe usar un perfilador. Por ejemplo, el caminador de montículos en JProfiler (descargo de responsabilidad: mi empresa desarrolla JProfiler) te ayudará a encontrar esos locales de hilo. Seleccione la clase de valor informada (com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty o com.sun.xml.bind.v2.ClassFactory) y muestre las referencias entrantes acumuladas. Una de ellas será una entrada java.lang.ThreadLocal$ThreadLocalMap$Entry . Seleccione los objetos referenciados para ese tipo de referencia entrante y cambie a la vista de asignaciones. Verá dónde se ha asignado la instancia. Con esa información puede decidir si puede hacer algo al respecto o no.

enter image description here

Mattias Jiderhamn tiene un excelente artículo de 6 partes que explica muy claramente la teoría y la práctica sobre las fugas del cargador de clases. Mejor aún, también lanzó un archivo jar que podemos incluir en nuestros archivos war. Lo probé en mis aplicaciones web, ¡y el archivo jar funcionó como un amuleto! El archivo jar se llama classloader-leak-prevention.jar. Para usarlo es tan simple como agregar esto a nuestro web.xml

  se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor  

y luego agregar esto a nuestro pom.xml

  se.jiderhamn classloader-leak-prevention 1.15.2  

Para obtener más información, consulte la página principal del proyecto alojada en GitHub o la Parte 6 de su artículo.

Crear subprocesos sin limpiarlos correctamente eventualmente te dejará sin memoria. He estado ahí, hecho eso.

Aquellos que todavía se preguntan por soluciones rápidas / soluciones alternativas, pueden ir a continuación:

  • Si ejecuta el tomcat independiente, mate javaw.exe o el proceso que lo soporta.
  • Si se está ejecutando desde eclipse, elimine eclipse.exe y java.exe o el proceso adjunto.
  • Aún no resuelto, verifique el administrador de tareas, es probable que el proceso que está causando esto se muestre con el mayor uso de memoria: realice su análisis y elimínelo.

Deberías ser bueno para volver a implementar las cosas y continuar sin problemas de memoria.

Supongo que probablemente haya visto esto, pero en caso de que ehcache doc recomiende poner la lib en tomcat y no en WEB-INF / lib .

Recomiendo inicializar locas hilo , en ServletRequestListener .

ServletRequestListener tiene 2 métodos: uno para inicialización y uno para destrucción.

De esta forma, puedes limpiar tu ThreadLocal . Ejemplo:

 public class ContextInitiator implements ServletRequestListener { @Override public void requestInitialized(ServletRequestEvent sre) { context = new ThreadLocal() { @Override protected ContextThreadLocal initialValue() { ContextThreadLocal context = new ContextThreadLocal(); return context; } }; context.get().setRequest(sre.getServletRequest()); } @Override public void requestDestroyed(ServletRequestEvent sre) { context.remove(); } } 

web.xml :

  ContextInitiator