我已经阅读了很多关于终结器如何工作的文章。以下是我的理解:如果一个类已经实现了finalize方法,那么Jvm会在该对象上创建一个Finalizer实例作为监视狗。
当GC运行时,它会标记要处置的对象并将它们添加到引用队列中,然后终结器线程将从队列中选择这些对象并执行它们的终结方法。
我的问题是:如何从堆转储中找到对象,其终结方法由于某种原因未完成并开始堆积引用队列?
参考队列是否按特定顺序?
答案 0 :(得分:0)
这可能不是您正在寻找的答案,但是您是否考虑过使用PhantomReference
而不是覆盖finalize()
?这是一个谈论它的article。
基本思路是不建议依靠finalyze()
方法进行预先清理,因为
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
,因此在将对象从内存中删除后,无法将其恢复。
答案 1 :(得分:0)
是的,您可以从堆转储中获取对象。
首先,终结器引用将从java.lang.ref.Finalizer.FinalizerThread#run
中的队列中删除,然后在runFinalizer
中,它将从方法remove
中未终结引用的双向链接列表中删除。
但是你可以找到这个引用,因为你知道GC根(它存在于FinalizerThread'堆栈中)
如何在日食MAT中找到它: