java - 如果 Java 的分代垃圾收集器遍历活动对象图,它们如何知道要在哪些对象上调用 finalize()?
问题描述
我的理解是 ParallelGC 和 G1 等 GC 是“世代”收集器。垃圾收集几乎是作为副产品发生的,因为您将所有活动对象移动到新的堆区域,而留在旧区域中的任何内容都将被简单地覆盖。这种“副产品”的解释很有意义,除了 Java 需要对死对象调用 finalize() 的部分。Java 是否还保留了每个堆区域中所有对象的单独列表,它可以与活动对象进行比较?
解决方案
是的,aGC
会跟踪所有这些对象及其类型。
事实上,GC 有一个专门的阶段,它只处理这些特殊的引用:WeakReference
、SoftReference
和PhantomReference
人工Finalizer
s。有的叫它Cleanup phase
,有的叫它Reference Processing
;作为其中的一部分,有Pre-cleapup
和Post-cleanup
阶段。
但想法是,当GC
在标记阶段遇到这样的“特殊”引用时,它会密切关注这些。首先,它分别跟踪它们(想想:将它们注册在一个 special 中List
)。当标记阶段完成时(至少对于某些GC
s),它将在暂停(stop-the-world)下分析这些引用。其中一些使用起来并不复杂:WeakReference
s 和SoftReference
s 是最简单的:如果 sreferent
是弱/软可访问的,则回收它并向ReferenceQueue
. PhantomReference
s 几乎相同(java-8 和 9 之间存在差异,但不再赘述)。
... Java 需要在死对象上调用 finalize()
你就在这里。最丑的是Finalizers
,主要是因为 aGC
必须要复活它得到的死掉的 Object,因为它需要调用finalize
一个实例,而那个实例是不可达的,或者死了;但 GC 无法回收它。所以GC
第一个复活对象,只是在下一个循环中立即杀死它,它将在这个实例上工作。不一定是第二个,一般来说可以是第 100 个周期;但它必须是涉及此特定实例的第二个。