java - Soft-/Weak-/PhantomReferences 清除对已引用跟踪对象的对象的引用的基本原理
问题描述
Soft
-、Weak
- 和s的文档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
,对象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
此而已。
推荐阅读
- jquery - Asp.Net Core 3.1-用Ajax搜索一个短语并建议5个相似的短语?
- bpmn - 带有有效负载的单个记录的 Camunda 工作流程
- javascript - While 和 For 循环 JavaScript 的输出差异 - Newbee
- node.js - 存储库类中未处理的承诺拒绝警告
- php - SimpleXML 循环遍历
- php - NGINX - 未找到文件
- c++ - 如何使用 push_back 将向量的向量从 3x3 修改为 4x4 并在 C++ 中插入?
- javascript - 重新添加事件监听器
- vue.js - 我可以使用数据中的设置动态更改子组件实例中的父函数名称吗?
- javascript - 如何通过 JavaScript 将表单数据发送到 API 帖子