我们首先要注意,这句话是从软引用和弱引用的文档中复制到 Java 9 幻像引用的文档中的,以适应在该版本中所做的更改,但不适合幻像引用,所以对于软引用和弱引用,可以更好地解释其背后的基本原理。
假设您有以下情况:
(weak)→ A
(weak)→ B (strong)→ A
从技术上讲,两者A
和B
都是弱可访问的,但我们可以通过在任一弱引用上调用get()
方法来改变这一点,以检索对其所指对象的强引用。
当我们对第一个弱引用执行此操作以检索对 的强引用时A
,对象B
将保持弱可达,但当我们这样做以获取对 的强引用时,由于来自的强引用B
,对象A
也将变得强可达B
到A
.
因此,我们有一个规则,如果对的弱引用A
被清除,则必须清除对的弱引用,否则,尽管弱引用已被清除,但仍有B
可能检索对A
via的强引用。并且为了安全起见,它必须以原子方式发生,因此没有可能的竞争条件允许在两个引用的清除之间检索对的引用。B
A
B
如前所述,这与虚拟引用的相关性较小,因为它们不允许检索引用,但没有理由对它们进行不同的处理。
这里的重点是,考虑到垃圾收集器的实际工作方式,这并不是真正的负担。他们必须遍历所有活动引用,即强可达对象,而所有没有遇到的东西,每次消除都是垃圾。所以在遍历过程中遇到弱引用时,不会遍历所指对象,而是记住引用对象。一旦完成遍历,它将遍历所有遇到的引用对象,并查看引用对象是否已被标记为可通过不同的路径到达。如果不是,则清除引用对象并将其链接以进行排队。
为了解决您的示例:
(strong)→ A
(weak)→ B (strong)→ A
在这里,B
无论对 的强引用如何,都是弱可达的A
。当您消除对 的强引用时A
,B
仍然是弱可达的并且可能会被排队。形式上,A
现在是弱可访问的,但是 JVM 永远不会在不检测到B
弱可访问的情况下检测到它。检测A
弱可达性的唯一方法是遍历从弱可达性开始的参考图B
。但是没有实现这样做。垃圾收集器将简单地清除对的弱引用,仅B
此而已。