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 [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"
访问“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"
重新部署/使用应用程序 10 次不为::
select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED"
在重新部署“Visual GC”插件下显示 PermGen 清理。
使用以前的开发设置运行需要一些东西::
JAVA_OPTS="-Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m"
生存 4-5 次重新部署。对较大 PermGen 的 OQL 查询给出了几个 Tomcat WebappClassLoader
,但检查实例表明没有通往 GC 的路径,并且当 PermGen 变满时它们会被清理。