我目前正在调查Tomcat 7(带有Oracle JDK 7)上的应用程序的一些类加载器泄漏。一个保持对Web应用程序类加载器的静态引用的类(因此导致类加载器不能在重新部署/重新启动时释放)是javax.xml.bind.DatatypeConverter
,它位于系统类加载器中并通过其保留静态引用来自Sun的jaxb-impl软件包的theConverter
字段到com.sun.xml.bind.DatatypeConverterImpl
。
以前有没有人见过这个问题?任何建议(除了在应用程序关闭时使用反射来清空静态字段)?
答案 0 :(得分:13)
事实证明,我的一个依赖项(com.sun.jersey:jersey-json
)已经引入了com.sun.xml.bind:jaxb-impl
,它负责系统类加载器 - > Application Classloader参考。排除这种依赖性解决了这个问题(因为JDK 7附带了一个合理的JAXB实现,它将在System CL中引用,这很好)。
答案 1 :(得分:0)
在开发期间重新部署后续Web应用程序时出现Tomcat 8问题警告:
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 [com.sun.xml.bind.v2.ClassFactory$1@79eb7926])
and a value of type [java.util.WeakHashMap]
(value [{class javax.xml.bind.annotation.W3CDomHandler=java.lang.ref.WeakReference@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"
在"安装"中访问指向对象的指向链接选项卡允许调用"查找最近的GC根"在"参考 部分"并将文本表示复制到clipboard ::
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
的Google搜索会导致此SO帖子。
提供的解决方案说com.sun.jersey:jersey-json
包请求JAXB API实现
来自com.sun.xml.bind:jaxb-impl
package ::
$ 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"
重新开发/使用应用程序10次,不会为::
select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED"
重新部署&#34; Visual GC&#34;插件显示PermGen清理。
使用以前的开发设置运行需要::
JAVA_OPTS="-Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m"
生存4-5重新部署。更大的PermGen的OQL查询给出了几个Tomcat的WebappClassLoader
但检查实例表明,没有GC的路径,当PermGen成为时,它们会被清除
满。