2012-07-06 59 views
7

我目前正在調查一些Tomcat 7上的應用程序的類加載器泄漏(帶有Oracle JDK 7)。一個保留對Web應用程序類加載器的靜態引用的類(並因此導致類加載器在重新部署/重新啓動時不被釋放)是javax.xml.bind.DatatypeConverter,它位於系統類加載器中,並通過其theConverter字段保留靜態引用至com.sun.xml.bind.DatatypeConverterImpl來自Sun的jaxb-impl軟件包。javax.xml.bind.DatatypeConverter泄漏類加載器?

有沒有人曾經觀察過這個問題?任何建議(除了使用反射來清空應用程序關閉時的靜態字段)?

+3

關於這個問題的更多細節在這組博客文章中給出:重新描述)。 – Guus 2013-07-25 17:02:13

回答

12

事實證明,我的一個依賴關係(com.sun.jersey:jersey-json)被拉到com.sun.xml.bind:jaxb-impl,它負責System Classloader - > Application Classloader的引用。排除依賴關係解決了這個問題(因爲JDK 7帶有一個明智的JAXB實現,它將在System CL中引用,這很好)。

0

Tomcat的8月刊上後續的Web應用程序開發的警告在重新部署:

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. 

我做內VisualVM的堆轉儲並打開它。

VisualVM的發現OQL標籤銷燬Web應用程序的類加載器通過查詢:

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

訪問指出鏈接對象「instalce」選項卡允許呼入「查找最近的GC根」在「參考 節」,並複製文字表述到剪貼板::

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是從Java SE和通過系統類加載器加載 該類(等標記(sticky class))。但指向由Web應用程序類加載器加載的類。

使用谷歌搜索關於com.sun.xml.bind.DatatypeConverterImpl導致此SO貼子。

附送的解決方案說com.sun.jersey:jersey-json包請求JAXB API實現 從com.sun.xml.bind:jaxb-impl包::

$ 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 

由於Java 7自帶自己的JAXB實現(JAXB RI的事實),我們不需要com.sun.xml.bind:jaxb-impl 包。添加排除相應的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> 

爲了達到結果在測試更快我的Tomcat減少內存::

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

Redeploing /使用的應用程序10次給沒有爲::

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

Under redeploys「Visual GC」插件顯示了PermGen清理。

與以前的開發設置運行需要的東西::

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

生存4-5重新部署。針對較大的PermGen的OQL查詢給出了多個Tomcat的WebappClassLoader ,但檢查實例顯示GC沒有路徑,並且它們在PermGen變爲 已滿時被清除。