2016-07-28 60 views
7

我已经阅读了许多文章如何终结者的作品。这里是我的理解:如果一个类已经实现了finalize方法,那么Jvm将创建一个Finalizer实例作为该对象的监视器。最终确定是持有大量的内存2.5 gig 4 g

当GC运行时,它会标记要放置的对象并将它们添加到引用队列中,然后终结器线程将从队列中选择这些对象并执行它们的finalize方法。

我的问题是:如何从堆转储找到对象,其中的finalize方法由于某种原因未完成,并开始堆积参考队列?

是否按特定顺序引用队列?

+2

只是想知道:什么是你的终结方法在做什么?为什么你有那么多想要使用方法的对象,至少在理论上,没有人应该依赖? – GhostCat

+0

从源代码看来,ReferenceQueue的工作方式与List类似 - 它包含Reference对象,每个Reference引用下一个Reference。也许第一个对象是你需要的。 也许你应该尝试在finalize方法上添加方面并添加一些日志记录(例如调用Finalize for xxx;完成完成) - 行中的最后一项将指向已开始完成的对象,但最终确定并未完成。 – ekaerovets

+0

我可能会用另一种方式去执行一个文本搜索,这些类有'finalize()'的非平凡实现 - 你的代码库中有太多候选人吗? – Hulk

回答

0

这可能不是您正在寻找的答案,但您是否考虑过使用PhantomReference而不是覆盖finalize()?这是一个谈论它的article

的基本思路是,不建议依靠finalyze()方法的验前的清理,因为

  • 你无法预测它什么时候会被调用。
  • 它从JVM中占用资源。
  • 它可以防止对象被垃圾收集。

PhantomReference提供了一种更简洁的方式来触发垃圾收集器清除对象时的操作。

Object objectToHandle = new Object(); 
ReferenceQueue queue = new ReferenceQueue(); 
PhantomReference reference = new PhantomReference(objectToHandle, queue); 

objectToHandle时将从存储器通过垃圾收集器被移除,其reference将被添加到所述queue。您可以通过拨打queue.remove()来检测,然后执行清理操作。

// will block until a reference becomes available 
Reference removedRef = queue.remove(); 
//.. you can now perform clean-up actions 

注:PhantomReference.get()总是返回null,所以不可能之后已经从内存中删除带回的对象。

0

是的,您可以从堆转储中获取对象。

首先,终结符ref将从java.lang.ref.Finalizer.FinalizerThread#run的队列中移除,然后在runFinalizer中,将从方法remove中的未连接的ref的双向链表中删除。

但是你可以找到这个裁判,因为你知道它GC根(它存在于FinalizerThread堆栈)

如何找到它在Eclipse MAT:由级Java

  1. 转到直方图和过滤器.lang.ref.Finalizer
  2. 右键单击带终结器的行 - >将最短路径合并到所有引用的gc根。
  3. 用FinalizerThread展开行(通常它应该包含一个对象java.lang。终结)
  4. 点击该扩展列,以及在检查面板,您可以点击属性选项卡上,最终确定对象将是指涉 enter image description here
+0

感谢您的回复。我没有看到检查员小组的选择。我如何打开检查员面板。 –

+0

没关系。非常感谢你的帮助。我能找到选项。 –

相关问题