java - 即使没有 gc 根,WebappClassLoader 内存泄漏

标签 java tomcat memory-leaks classloader yourkit

HERE IS THE HEAD DUMP (UPDATED ON 10/29/2013)

我在一个网络应用中工作:

  • Tomcat 7.0.24
  • Java 6
  • Spring 3(使用 aop - cglib)
  • 基于 Log4j 的 SLF4J
  • Oracle 一致性

经过大量工作,我设法删除了所有对类加载器的强引用,现在它是垃圾收集器的候选者。那么,内存泄漏解决了吗?当然不是!因为在几次热部署之后,由于 PermGen 空间出现了 OOME。

感谢 Yourkit,我能够检查 WebappClassLoaderPending Finalization 这意味着它正在终结队列中等待(实际上,不是 WebappClassLoader 本身就是他的一个referents)。检查内存快照时,我发现了几个对 Oracle Coherence 类的 Finalizer 引用... enter image description here

这看起来很“好”:Coherence 对象正在等待垃圾回收,这要归功于移除所有强引用所做的所有艰苦工作(杀死所有 coherence 线程,移除 java 安全提供程序等)。我认为这里没有什么可做的。

所以,我在考虑一些 finalize 执行会破坏某些东西,然后不允许清空终结器队列。但奇怪的是,使用 JMX 或 jmap -finalizerinfo 终结器队列似乎是空的!这一切都非常令人困惑,所以我一直在其他地方搜索......

你认为这是这里要做的事吗? 我读过一些关于 CGLIB enhancing the finalize method 的东西.如果我有权访问 Enhancer,我可以按照说明创建一个回调过滤器 here但我不知道如何使用 Spring AOP 来管理它。

好吧,在其他地方搜索,我发现了几个来自 java.lang.reflect.Proxy 的弱引用。这些是 jdk 动态代理吧?或者它们与内省(introspection)内存泄漏有关?弱引用?

enter image description here

信息:我正在使用 Spring 的上下文监听器来刷新 Instrospector 的缓存 (java.beans.Introspector.flushCaches())。 我还能用它做什么?

让我们继续。

然后,我们还有来自 java.io.ObjectStreamClass$Caches 的其他几个弱引用。我的很多业务对象都有这种弱引用。

enter image description here enter image description here

也许我需要刷新这些缓存。 但是如何呢??

然后我们有这些与 com.sun.internal.ResourceManagerjava.util.logging.Loggingjava.lang.reflect 相关的弱引用。代理

enter image description here

我能用这个弱引用做什么?我需要担心这个还是问题出在终结器队列上?任何线索都会有帮助......真的:-D

啊,还有一件事,我从 tomcat 的“主”线程中发现了一个弱引用,它永远不会被 tomcat 更新。我知道我的应用程序可以在某些 tomcat 线程中保留一些线程局部变量,但是 tomcat 7 renew these threads to avoid class loader memory leaks . enter image description here

我认为这是我的内存快照中最奇怪的东西,但这是弱引用吗?我可以用它做什么?

编辑:阅读java.lang.ref javadoc我发现了这个:

An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.

那么,弱引用在实现finalize方法时是否可以保留堆中的对象?

与此同时,我找到了这个问题的答案,我设法删除了所有对我的类加载器的弱引用,除了两个:ClassLoaderLogManager.classLoaderLoggers 和与 tomcat 线程相关的那个。

注意:实际上,我设法删除了第一个,但此引用在取消部署之后/期间由 tomcat 再次设置。

编辑:PLUMBR 结果

我已经尝试过 plumbr,但在 Web 控制台上没有任何报告。标准输出上只有这条消息

Dumping heap to /opt/tomcat7/headdumps/java_pid9478.hprof ...
Heap dump file created [348373628 bytes in 3.984 secs]
#
# An unexpected error has been detected by Java Runtime Environment:
#
#  Internal Error (javaCalls.cpp:40), pid=9478, tid=1117813056
#  Error: guarantee(!thread->is_Compiler_thread(),"cannot make java calls from the compiler")
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode linux-amd64) [thread 1110444352 also had an error]
# An error report file with more information is saved as:
# [thread 1110444352 also had an error]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#
******************************************************************************
*                                                                            *
* Plumbr has noticed that JVM has thrown an OutOfMemoryError: PermGen space. *
*                                                                            *
* You can increase PermGen size with -XX:MaxPermSize parameter.              *
* If you encountered this error after a redeploy, please read next article:  *
* http://plumbr.eu/blog/what-is-a-permgen-leak                               *
*                                                                            *
******************************************************************************

最佳答案

我认为 Yourkit 将您引向了错误的道路。

我已经使用 Eclipse 内存分析器查看了您的堆转储。它表明,WebappClassLoader 被类 com.inovasoftware.iap.data.access.platform.datarepository.CoherenceDataRepository$$EnhancerByCGLIB$$180c0a4e 引用,该实例在某个线程局部变量中处于 Activity 状态。一些谷歌搜索显示: https://hibernate.atlassian.net/browse/HHH-2481

因此升级 Hibernate 版本可能会有帮助。

MAT screenshot

关于java - 即使没有 gc 根,WebappClassLoader 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19470328/

相关文章:

java - 设置tomcat的最大堆空间

c++ - 修复我自己的双向链表中的内存泄漏

c++ - 为什么我的 DLL 在使用 MFC 作为 Visual Studio 2010 中的 DLL 的 MFC SDI 程序中使用时会泄漏?

java - 从 Java 读取 XML 字符串

java - 如何从 int 数组向下舍入到最接近的整数?

java - Math.pow(7,5) 与 7*7*7*7*7 不同——为什么?

java - 打印两次

java - 如何在 Spring 管理 hibernate session

tomcat - 符号链接(symbolic link)到 log4j.xml

c++ - 漏线的症状