首页 > 解决方案 > 如果 Java 的分代垃圾收集器遍历活动对象图,它们如何知道要在哪些对象上调用 finalize()?

问题描述

我的理解是 ParallelGC 和 G1 等 GC 是“世代”收集器。垃圾收集几乎是作为副产品发生的,因为您将所有活动对象移动到新的堆区域,而留在旧区域中的任何内容都将被简单地覆盖。这种“副产品”的解释很有意义,除了 Java 需要对死对象调用 finalize() 的部分。Java 是否还保留了每个堆区域中所有对象的单独列表,它可以与活动对象进行比较?

标签: javagarbage-collectionheap-memoryg1gcfinalize

解决方案


是的,aGC会跟踪所有这些对象及其类型。

事实上,GC 有一个专门的阶段,它只处理这些特殊的引用:WeakReferenceSoftReferencePhantomReference人工Finalizers。有的叫它Cleanup phase,有的叫它Reference Processing;作为其中的一部分,有Pre-cleapupPost-cleanup阶段。

但想法是,当GC在标记阶段遇到这样的“特殊”引用时,它会密切关注这些。首先,它分别跟踪它们(想想:将它们注册在一个 special 中List)。当标记阶段完成时(至少对于某些GCs),它将在暂停(stop-the-world)下分析这些引用。其中一些使用起来并不复杂:WeakReferences 和SoftReferences 是最简单的:如果 sreferent是弱/软可访问的,则回收它并向ReferenceQueue. PhantomReferences 几乎相同(java-8 和 9 之间存在差异,但不再赘述)。

... Java 需要在死对象上调用 finalize()

你就在这里。最丑的是Finalizers,主要是因为 aGC必须要复活它得到的死掉的 Object,因为它需要调用finalize一个实例,而那个实例是不可达的,或者死了;但 GC 无法回收它。所以GC第一个复活​​对象,只是在下一个循环中立即杀死它,它将在这个实例上工作。不一定是第二个,一般来说可以是第 100 个周期;但它必须是涉及此特定实例的第二个。


推荐阅读