5

Java允许编写:

new PhantomReference(new Object(), null)

在这种情况下new Object()会被收集吗?

据我了解,幻影参考是finalize() 方法使用的替代方法。

在队列中出现参考后,我需要做一些额外的动作然后运行clear()

java doc 保留:

可以使用空队列创建幻像引用,但这样的引用完全没有用:它的 get 方法将始终返回 null,并且由于它没有队列,因此永远不会入队

如果它永远不会入队是什么意思?

据我了解,这意味着在 finalize 方法调用之后不会将引用添加到 referenceQueue 中。因此可能会导致:
1. 对象内存将被立即清除
2. 对象内存不会被清除

哪种情况正确?

4

1 回答 1

9

好吧,正如您自己注意到的那样, aPhantomReference不会自动清除。这意味着只要您保持对 的强引用PhantomReference,所指对象将保持幻象可达。正如文档所说:“<em>通过幻像引用可访问的对象将保持不变,直到所有此类引用都被清除或自身变得不可访问。”</p>

然而,考虑到对象何时不可访问(现在我正在谈论“幻影引用本身”)可能会导致许多意外。尤其是参考对象很可能不会提供有用的操作,随后将不会再被触及。

由于PhantomReference没有队列的永远不会入队并且它的get()方法总是会返回null,所以它确实没有用。

那么为什么构造函数允许构造这样一个无用的对象呢?好吧,第一个版本(1.2)的文档指出,NullPointerException如果队列是null. 该语句一直持续到 1.4,然后Java 5是第一个包含该语句的版本,您可以在没有队列的情况下构造 a PhantomReference,尽管它没用。我的猜测是,它总是继承了超类允许null队列的行为,这与文档相矛盾,而且很晚才被注意到,因此决定保持兼容并调整文档而不是改变行为。


更难回答的问题是为什么 aPhantomReference没有自动清除。文档只说幻影可达对象将保持不变,这是未清除的结果,但没有解释为什么这有任何相关性。

这个问题已在 SO 上提出,但答案并不令人满意。它说“允许在对象被垃圾收集之前执行清理”,这甚至可能符合做出该设计决策的人的心态,但由于清理代码无法访问对象,因此它是否在之前执行或执行无关紧要对象被回收后。如上所述,由于该规则取决于对象的可达性,而PhantomReference对象的可达性受优化代码转换的影响,甚至可能PhantomReference在清理代码完成之前,对象与实例一起被回收,而没有人注意到。

早在 2013 年,我还在HotSpot 开发者邮件列表中发现了一个类似的问题,该问题也没有答案。

有增强请求JDK-8071507来改变这种行为并PhantomReference像其他人一样清除 s,它对于 Java 9 具有“固定”状态,实际上,它的文档现在声明它们像任何其他参考一样被清除。

不幸的是,这意味着我的帖子开头的答案从 Java 9 开始是错误的。然后,无论您是否保持对实例的强引用,new PhantomReference(new Object(), null)都会使新创建的实例立即符合垃圾收集条件。ObjectPhantomReference

于 2017-02-01T19:02:57.473 回答