如何识别JNI全局引用内存泄漏的原因?
我正在使用Tomcat,在停止我的Web应用程序之后,仍然会引用我的Web应用程序的类加载器实例。 结果是不会释放大量的内存(主要与静态数据相关)。 迟早会导致OutOfMemoryError
。
我进行了heap dump
,我意识到它由JNI全局引用保存 , 可以防止类加载器被垃圾回收 。
我的应用程序不使用JNI 。 我也没有使用Apache Tomcat Native Library 。 我正在使用Sun / Oracle JDK。
我想跟踪这个全球参考的原因/来源。 (我的猜测是JVM内部引用了类加载器 – 但是为什么/在哪里?)。
题:
- 有哪些方法/工具集可以实现这一目标?
UPDATE
似乎bestsss是正确的,jvm调试模式引入了JNI全局引用。 这帮助了我,但它没有回答这个问题所以我仍然很想回答一个可能对将来有帮助的问题。
除了明显的案例:线程,还有一个:
您是否在调试模式下使用您的应用程序?
除了系统之外,JVM不保留对任何类加载器的引用,但它与您无关。 其余的JNI引用是Threads或只是调试持有的对象(前提是你不使用JNI并自己锁定对象)。
JNI引用只是根,编辑您的答案并发布这些引用所持有的对象。
我要做的第一件事是使用-Xcheck:jni
运行,看看它是否有任何结果。 我不指望它; 听起来JNI并没有发生任何奇怪的事情,只是错误地使用它。 但是,确保这一点很好。
如果您使用的是Sun JVM,我认为您可以执行-XX:TraceJNICalls
,以便在JNI调用发生时获得压倒性的列表。 这应该可以让你了解正在进行的调用,并从那里开始研究制作它们的原因,以及为什么会导致问题。
我能想到的两个工具。
- 如果使用
jmap
创建堆转储并使用jhat
进行分析,则可以使用某些function来跟踪对象的引用。 这两个工具都带有JDK(JDK_HOME / bin)。 - 另一种方法是附加调试器并使用它。 我使用eclipse,一旦变量在变量窗口中,你可以右键单击它并选择“所有引用”。
JRockit任务控制: http : //download.oracle.com/docs/cd/E13150_01/jrockit_jvm/jrockit/tools/index.html
一个很好的GUI工具,可以帮助您快速找到它。
你可以试试jstack 。
也许列出的堆栈跟踪之一会向您显示全局引用的来源。