2011-10-17 24 views
36

Cuando REDEPLOY mi aplicación en Tomcat, tengo el siguiente problema:pérdida de memoria cuando la redistribución de aplicación en Tomcat

The web application [] created a ThreadLocal with key of type 
[java.lang.ThreadLocal] (value [[email protected]]) 
and a value of type [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty] 
(value [[email protected]a183d2]) 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 solicitud. Esto también parece dar como resultado la siguiente excepción.

 SEVERE: The web application [] created a ThreadLocal with key of type [null] 
    (value [[email protected]]) and a value of type [java 
    .util.WeakHashMap... 

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

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

Háganme saber si estas advertencias tienen algún impacto funcional o pueden ser ignoradas? Utilicé la opción "Buscar pérdidas de memoria" en tomcat manager y dice "No se encontraron pérdidas de memoria"

+1

Las advertencias significa que su capacidad de implementar la aplicación sin necesidad de reiniciar Tomcat en sí es limitado. Los webapps han estado plagados durante mucho tiempo por fugas de memoria de este tipo. No tienen ningún impacto a menos que vuelvas a implementar las aplicaciones. No lo sé, pero sospecho que estos mensajes en la salida de Tomcat, que comenzaron a aparecer uno o dos años más, son para presionar a los desarrolladores de frameworks para que comiencen a limpiar correctamente después de ellos mismos al reiniciar. –

Respuesta

36

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 clases de aplicaciones web establece ThreadLocal con una instancia cuya clase fue cargada por el cargador de clases de aplicaciones web, el hilo de servlet contiene una referencia a esa instancia. Esto significa que el cargador de clases no será basura.

Tomcat realiza una serie de detecciones de este tipo, consulte here for more information. Limpiar locales de hilo es difícil, debe llamar al remove() en el ThreadLocal en cada uno de los hilos a los que se accede desde. 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 de hilo, debe utilizar un generador de perfiles. Por ejemplo, el caminador de montículos en JProfiler (descargo de responsabilidad: mi empresa desarrolla JProfiler) lo ayudará a encontrar esos locales con temas. 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. Uno de ellos será un 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

+2

Como veo, parece que JProfiler no es una solución gratuita y de código abierto. ¿Puede sugerir alguna otra alternativa? – Raghav

+3

Pruebe [VisualVM] (http://visualvm.java.net/). – timomeinen

+0

@Raghav Eclipse Memory Analyzer también es ideal para analizar volcados de almacenamiento dinámico. http://www.eclipse.org/mat/ – Phil

2

me adivina que probablemente ha visto esto, pero por si acaso doc ehcache recomienda a poner el lib de Tomcat y no en WEB-INF/lib: http://ehcache.org/documentation/integrations/tomcat

+0

Enlace actualizado: http://ehcache.org/generated/2.9.0/html/ehc-all/#page/Ehcache_Documentation_Set%2Fco-tcat_tomcat_issues_and_practices.html%23wwconnect_header luego scroll hasta 'pérdida de memoria del cargador de clase' –

3

Creación de Hilos sin limpiarlos correctamente se eventualmente te agota la memoria: estado allí, hecho eso.

Los que todavía se pregunta para una rápida solución/solución, puede ir a continuación:

  • Si se ejecuta el gato independiente, matar javaw.exe o el proceso que lo lleva.
  • Si se ejecuta desde eclipse, elimine eclipse.exe y java.exe o el proceso que lo contiene.
  • Aún no resuelto, verifique el administrador de tareas, es probable que el proceso que está causando esto se muestre con la memoria más alta uso - Haga su análisis y elimine eso.

Usted debe ser bueno para redistribuir el material y proceder sin problemas de memoria.

6

Mattias Jiderhamn tiene una excelente 6-part article 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 añadir esto a nuestra Web.xml

<listener> 
    <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor</listener-class> 
</listener> 

y luego añadir esta en nuestro pom.xml

<dependency> 
    <groupId>se.jiderhamn</groupId> 
    <artifactId>classloader-leak-prevention</artifactId> 
    <version>1.15.2</version> 
</dependency> 

Para obtener más información, consulte la project home page hosted on GitHub o Part 6 of his article

1

Recomiendo inicializar thread locals, en un ServletRequestListener.

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

De esta manera, puede limpiar su ThreadLocal. Ejemplo:

public class ContextInitiator implements ServletRequestListener { 
    @Override 
    public void requestInitialized(ServletRequestEvent sre) { 
     context = new ThreadLocal<ContextThreadLocal>() { 
      @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:

<listener> 
    <listener-class>ContextInitiator</listener-class> 
</listener> 
Cuestiones relacionadas