【问题标题】:How can I remove a “Java Frame” GC Root reference to a Runnable when I dump a heap in jvisualvm?当我在 jvisualvm 中转储堆时,如何删除对 Runnable 的“Java 框架”GC 根引用?
【发布时间】:2011-10-27 18:04:39
【问题描述】:

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

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

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

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

这是怎么回事?

【问题讨论】:

  • 在“Instances”面板中,您可以选择您认为应该收集的实例,右键单击,然后从上下文菜单中选择“Show in Threads”吗?如果有,它说明了什么?

标签: java memory-leaks garbage-collection jvisualvm


【解决方案1】:

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


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

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

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

清理target 的声明,使其在循环内解决问题。

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

【讨论】:

  • @ErickRobertson 您是否使用来自 JSE 的 Executor?哪个实现类?
  • 如果它存储在 Java 核心类的局部变量中,那不会出现在 jvisualvm 堆转储中吗?系统中的每个其他对象都有其在堆中所有引用的完整列表。所以我只能假设对这个对象的任何引用都来自堆之外的某个地方。
  • 宾果游戏!这不是完全相同的模式,但这正是正在发生的事情。引用位于线程堆栈中的局部变量中,当线程等待另一个Runnable 时,该变量仍被持有。感谢您的精彩回答!
  • 对了,我也要去看看Executor服务。当我第一次看到它时,我完全被它淹没了,我并不需要它的大部分功能。现在我看它,它似乎很简单。似乎只有几行代码可以交换和测试它,所以它在我的后台项目列表中。以两种方式对其进行基准测试并确定性能更好的解决方案将很容易。再次感谢您的帮助和学习。
【解决方案2】:

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

【讨论】:

  • 只要有工作需要完成,对象就会被分配给线程池。在我已经转储线程的状态下,对象已完全未引用并且线程池处于空闲状态。代码中没有对该对象的剩余引用。运行它的最后一个线程是否会保留对它运行的最后一个可运行对象的一些内部引用?
  • 这当然是可能的。当然不应该。作为一个实验,如果你制作一个包装器 Runnable,它只是委托给你的真实 Runnable,然后你手动删除包装器 Runnable 中对你真实 Runnable 的引用怎么办?你的 runnable 是否被 GCed 并且包装器仍然存在?
  • 另外,如果你停止执行器会发生什么,如果你让它执行另一个可运行的会发生什么?这个会发布吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 2021-11-12
相关资源
最近更新 更多