2012-07-06 19 views
7

Actualmente estoy investigando algunas fugas del cargador de clase de una aplicación en Tomcat 7 (con Oracle JDK 7). Una clase que mantiene una referencia estática al cargador de clases de la aplicación web (y hace que el cargador de clases no se libere al volver a implementar/reiniciar) es javax.xml.bind.DatatypeConverter, que vive en el cargador de clases del sistema y mantiene una referencia estática a través del campo theConverter al com.sun.xml.bind.DatatypeConverterImpl del paquete jaxb-impl de Sun.javax.xml.bind.DatatypeConverter cargadores de clase con fugas?

¿Alguien ha observado este problema anteriormente? ¿Alguna sugerencia (excepto para usar la reflexión para anular el campo estático al apagar la aplicación)?

+3

Más detalles sobre el problema se dan en este conjunto de publicaciones de blog: http://java.jiderhamn.se/category/classloader-leaks/ (busque 'jaxb' en el texto para una descripción del problema que usted ' re describiendo). – Guus

Respuesta

12

Como se vio después, una de mis dependencias (com.sun.jersey:jersey-json) extrajo com.sun.xml.bind:jaxb-impl, que era responsable del System Classloader -> Application Classloader reference. Excluir esa dependencia resolvió el problema (ya que JDK 7 viene con una implementación JAXB sensata, a la que se hará referencia dentro del System CL, que está bien).

0

Tomcat edición del 8 de advertencia en la posterior aplicación web redistribuir durante el desarrollo:

org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks 

SEVERE: The web application [rsnetlombard] created a ThreadLocal with key of type 
[com.sun.xml.bind.v2.ClassFactory$1] (value [[email protected]]) 
and a value of type [java.util.WeakHashMap] 
(value [{class java[email protected]525eec52}]) 
but failed to remove it when the web application was stopped. 
Threads are going to be renewed over time to try and avoid a probable memory leak. 

hago volcado del montón dentro VisualVM y abrirlo.

VisualVM encontrar el cargador de clases destruida aplicación web en la pestaña NCO por consulta:

select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED" 

Visitante señaló enlace a oponerse en la pestaña "instalce" permite llamada "Encuentra más cercano raíz GC" en "referencia sección" y copiar representación textual al portapapeles ::

this  - value: org.apache.catalina.loader.WebappClassLoader #3 
<- <classLoader>  - class: com.sun.xml.bind.DatatypeConverterImpl, value: org.apache.catalina.loader.WebappClassLoader #3 
    <- <class>  - class: com.sun.xml.bind.DatatypeConverterImpl, value: com.sun.xml.bind.DatatypeConverterImpl class DatatypeConverterImpl 
    <- theConverter (sticky class)  - class: javax.xml.bind.DatatypeConverter, value: com.sun.xml.bind.DatatypeConverterImpl #1 

javax.xml.bind.DatatypeConverter es desde Java sE y esa clase cargado por el cargador de clases del sistema (y por lo marcó (sticky class)). Pero apunte a la clase cargada por el cargador de clases de la aplicación web.

Google buscando alrededor de com.sun.xml.bind.DatatypeConverterImpl lleva a esta publicación SO.

solución suministrada dicen que la aplicación com.sun.jersey:jersey-json paquete de solicitud de API JAXB de com.sun.xml.bind:jaxb-impl paquete ::

$ mvn dependency:tree 
... 
[INFO] +- com.sun.jersey:jersey-json:jar:1.8:compile 
[INFO] | +- org.codehaus.jettison:jettison:jar:1.1:compile 
[INFO] | | \- stax:stax-api:jar:1.0.1:compile 
[INFO] | +- com.sun.xml.bind:jaxb-impl:jar:2.2.3-1:compile 
[INFO] | | \- javax.xml.bind:jaxb-api:jar:2.2.2:compile 
[INFO] | |  \- javax.xml.stream:stax-api:jar:1.0-2:compile 
[INFO] | +- org.codehaus.jackson:jackson-core-asl:jar:1.7.1:compile 
[INFO] | +- org.codehaus.jackson:jackson-mapper-asl:jar:1.7.1:compile 
[INFO] | +- org.codehaus.jackson:jackson-jaxrs:jar:1.7.1:compile 
[INFO] | \- org.codehaus.jackson:jackson-xc:jar:1.7.1:compile 

Debido a Java 7 viene con la propia aplicación JAXB (JAXB RI por el hecho de) que no necesitamos com.sun.xml.bind:jaxb-impl paquete. Agregar excluyo a la parte correspondiente de pom.xml ::

<dependency> 
     <groupId>com.sun.jersey</groupId> 
     <artifactId>jersey-json</artifactId> 
     <version>${jersey.version}</version> 
     <exclusions> 
      <exclusion> 
       <groupId>com.sun.xml.bind</groupId> 
       <artifactId>jaxb-impl</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 

con el fin de alcanzar los resultados más rápidos en la prueba reduzco la memoria Tomcat ::

JAVA_OPTS="-Djava.awt.headless=true -Xmx212m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=66m" 

Redeploing/aplicación utilizando 10 veces doy ninguna para ::

select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED" 

En redespliegue, el complemento "Visual GC" muestra las limpiezas de PermGen.

Correr con la configuración anterior de desarrollo requieren algo ::

JAVA_OPTS="-Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m" 

para sobrevivir 4-5 vuelve a desplegar. La consulta OQL para PermGen más grande proporciona varios Tomcat WebappClassLoader pero examinando instancias que muestran que no hay una ruta a GC y se limpian cuando PermGen se convierte en completo.