当我在jvisualvm中转储堆时,如何删除对Runnable的“Java Frame”GC根引用?

时间:2011-10-27 18:04:39

标签: java memory-leaks garbage-collection jvisualvm

我正在使用jvisualvm检查应用程序中的内存泄漏。当我进行堆转储时,有时会有几个对象被打开,应该被垃圾收集。

当我对它们执行“显示最近的GC根”命令时,它向我显示根是我定义的类,它实现了Runnable接口。该引用列为(java frame),我知道它与线程有关。当我展开此节点的树时,它会打开并显示<no references>。所以很明显,这不是我保持开放的参考,而是Java内部的东西。

jvisualvm中列出的GC Root对象的类型为AnalyticNode extends Node,而Node implements Runnable为{{1}}。尽管使用了“frame”一词,但这个根对象绝不与AWT,Swing或任何重量级用户界面组件有任何关系。在这种情况下,单词“frame”指的是线程。

Java是否会保留对最后一个Runnable的引用?有什么方法可以告诉Java发布这个引用,以便可以正确地为我的堆转储收集垃圾?

这里发生了什么?

2 个答案:

答案 0 :(得分:4)

在这种情况下,&#34;框架&#34;指的是堆栈框架。听起来像Runnable,而不是(或除此之外)是正在运行的线程的目标,它存储在执行线程的堆栈中的帧中的局部变量中。当与帧相关联的方法返回时,它将有资格进行收集。


根据后续评论,我的猜测是,在您的自定义线程池中,有一个Runnable被分配到的局部变量。它可能在一个范围太大(在循环之外)并且在循环的每次迭代之后没有被清除(分配null)。

我可以在工作线程中重现与这样的代码描述匹配的情况:

Runnable target = null;
while (true) {
  target = queue.take();
  target.run();
}

清理target的声明以使其处于循环内部可以解决问题。

我建议从核心Java切换到Executor实现,或者如果要修复它,可以发布自定义线程池的相关代码。

答案 1 :(得分:1)

您对自己创建的对象做了什么?你创建了一个线程并指向它吗?在这种情况下,您必须通过允许run()中的代码完成运行来确保线程已停止。