好吧,正如您自己注意到的那样, 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)
都会使新创建的实例立即符合垃圾收集条件。Object
PhantomReference