Soft-/Weak-/PhantomReferences 清除对引用被跟踪对象的对象的引用的理由

Rationale for Soft-/Weak-/PhantomReferences clearing references to objects which have reference to tracked object

Soft-, Weak- and PhantomReference 的文档都包含类似于以下内容的一行(摘自 PhantomReference):

At that time it will atomically clear all phantom references to that object and all phantom references to any other phantom-reachable objects from which that object is reachable.

让我感到困惑的部分是关于其他幻影可及对象的部分。

如果我理解正确的话,这描述了这个案例:
对象:

参考文献:

-> A
-P-> B -> A

所以出于某种原因,垃圾收集器尚未确定 B 仅是幻象可达的。现在,如果 A 变为幻影可达并且垃圾收集器检测到这一点,则需要(根据上面引用的文档)清除对 B.

的引用

文档要求这样做有什么理由吗?看来如果其他厂商要开发一个JVM,这将是一个相当大的负担。

我们首先要注意,这句话是从软引用和弱引用文档复制到 Java 9 的幻影引用文档,以适应该版本中所做的更改,但不是非常适合虚引用,所以它背后的基本原理可以更好地解释软引用和弱引用。

假设您有以下情况:

(weak)→ A
(weak)→ B (strong)→ A

从技术上讲,AB 都是弱可达的,但我们可以改变这一点,在任一弱引用上调用 get() 方法,以检索对其所指对象的强引用.

当我们在第一个弱引用上执行此操作以检索对 A 的强引用时,对象 B 将保持弱可达性,但当我们执行此操作以获取对 A 的强引用时B,由于从 BA 的强引用,对象 A 也将变得强可达。

因此,我们有一个规则,如果对A的弱引用被清除,对B的弱引用必须被清除,否则,将有可能检索到一个强引用尽管对 A 的弱引用已被清除,但通过 BA 的引用已被清除。为了安全起见,它必须以原子方式发生,因此不可能存在允许在两个引用的间隙之间检索对 B 的引用的竞争条件。

如前所述,这与幻影引用的相关性较小,因为它们不允许检索引用,但没有理由区别对待它们。

这里的重点是,考虑到垃圾收集器的实际工作方式,这并不是实际的负担。他们必须遍历所有活动引用,即强可达对象,并且所有未遇到的对象都是每次消除的垃圾。所以在遍历中遇到弱引用时,不会遍历引用对象,而是记住引用对象。完成遍历后,它将 运行 遍历所有遇到的引用对象,并查看引用对象是否已被标记为可通过不同路径访问。如果不是,则清除引用对象并链接入队。

举个例子:

(strong)→ A
(weak)→ B (strong)→ A

在这里,无论对 A 的强引用如何,B 都是弱可达的。当您消除对 A 的强引用时,B 仍然是弱可达的并且可能会排队。形式上,A 现在是弱可达的,但是 JVM 永远不会检测到 B 也是弱可达的。检测 A 是弱可达的唯一方法是遍历从弱可达 B 开始的参考图。但是没有实现这样做。垃圾收集器将简单地清除对 B 的弱引用,仅此而已。