Soft
、Weak
- 和PhantomReference
的文档都包含以下一行类似(取自PhantomReference
):
届时,它将以原子方式清除对该对象的所有幻像引用,以及对可从中访问该对象的任何其他幻像可访问对象的所有幻像引用。
让我感到困惑的部分是关于其他可到达的幻影对象的部分。
如果我理解正确,这描述了这种情况:对象:
- 一个
- 乙
引用:
->
: 强参考-P->
: 幻影参考
-> A
-P-> B -> A
因此,由于某种原因,垃圾回收器尚未确定B
只能幻像访问。现在,如果A
变得幻像可访问并且垃圾回收器检测到这一点,则还需要(根据上面引用的文档)清除对B
的引用。
文档要求这样做有什么原因吗?看起来,如果其他供应商要开发JVM,这将是一个负担。
我们首先必须注意,这句话是从 Java 9 的软引用和弱引用文档中复制的,以适应该版本中所做的更改,但不适合虚拟引用,因此对于软引用和弱引用,可以更好地解释其背后的基本原理。
假设您遇到以下情况:
(weak)→ A
(weak)→ B (strong)→ A
从技术上讲,A
和B
都是弱可访问的,但我们可以通过在任一弱引用上调用get()
方法来更改它,以检索对其引用的强引用。
当我们在第一个弱引用上执行此操作时,为了检索对A
的强引用,对象B
将保持弱可访问性,但是当我们这样做以获得对B
的强引用时,由于从B
到A
的强引用,对象A
也将变得强可访问。
因此,我们有规则,如果清除了对A
的弱引用,则必须清除对B
的弱引用,否则,尽管对A
的弱引用已被清除,但仍可以通过B
检索对A
的强引用。为了安全起见,它必须以原子方式发生,因此没有可能的竞争条件允许在两个引用的清除之间检索B
引用。
如前所述,这与幻像引用的相关性较小,因为它们不允许检索引用,但没有理由区别对待它们。
这里的重点是,考虑到垃圾收集器的实际工作方式,这不是一个实际的负担。它们必须遍历所有实时引用,即强可访问的对象,以及所有未遇到的内容,每次消除都是垃圾。因此,当在遍历过程中遇到弱引用时,它不会遍历引用对象,但会记住引用对象。完成遍历后,它将遍历所有遇到的参考对象,并查看引用是否已标记为可通过其他路径到达。否则,将清除引用对象并链接以进行排队。
要解决您的示例,请执行以下操作:
(strong)→ A
(weak)→ B (strong)→ A
在这里,无论对A
的强引用如何,B
都是微弱可到达的。当您消除对A
的强引用时,B
仍然可弱访问,并且可能会排队。从形式上讲,A
现在是弱可访问的,但是如果不检测到B
也是弱可访问的,JVM将永远不会检测到这一点。检测A
是弱可访问的唯一方法是从弱可访问B
开始遍历参考图。但是没有实现这样做。垃圾回收器将简单地清除对B
的弱引用,仅此而已。