4

jvisualvm用来检查我的应用程序中的内存泄漏。当我进行堆转储时,有时会有几个对象保持打开状态,这些对象应该被垃圾收集。

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

jvisualvm 中列出的 GC Root 对象的类型AnalyticNode extends NodeNode implements Runnable. 这个根对象与 AWT、Swing 或任何重量级用户界面组件没有任何关系,尽管使用了“框架”这个词。在这种情况下,“框架”一词指的是线程。

那么 Java 是否保留了对最后一个 Runnable 的引用,该引用会保持这个打开状态?有什么方法可以告诉 Java 释放这个引用,以便可以为我的堆转储正确收集垃圾?

这里发生了什么?

4

2 回答 2

7

在此上下文中,“帧”指的是堆栈帧。听起来像这样Runnable,而不是(或除此之外)是正在运行的线程的目标,而是存储在正在执行的线程堆栈上的帧中的局部变量中。当与框架关联的方法返回时,它将有资格被收集。


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

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

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

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

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

于 2011-10-27T18:12:01.977 回答
1

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

于 2011-10-27T18:09:00.143 回答