Java允许编写:

new PhantomReference(new Object(), null)

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

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

在队列中出现引用之后,我需要执行一些其他操作,然后运行clear()
Java Doc保留:

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

如果它永远不会排队,那意味着什么?

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

哪种情况正确?

最佳答案

嗯,就像您注意到的那样,PhantomReference不会自动清除。这意味着只要您对PhantomReference保持强烈引用,该参照对象就可以幻影地到达。正如documentation所说:“通过幻像引用可访问的对象将保持不变,直到所有此类引用被清除或自身无法访问为止。”

但是,考虑何时无法访问对象(现在我正在谈论“幻像引用本身”)可能会导致很多意外。尤其是由于很有可能该参考对象没有提供有用的操作,因此以后将不再被触摸。

由于没有队列的PhantomReference永远不会入队,并且其get()方法将始终返回null,因此确实没有用。

那么,为什么构造函数允许构造这样一个无用的对象呢?好吧,the documentation of the very first version (1.2)声明如果队列是NullPointerException,它将抛出一个null。该语句一直持续到1.4,然后Java 5是第一个包含该语句的版本,尽管无用,您也可以无队列地构造PhantomReference。我的猜测是,它始终继承超类的行为,即允许null队列,与文档相矛盾,并且很晚才注意到,是决定保持兼容性并改编文档,而不是改变行为。

问题(甚至更难回答)是,为什么不能自动清除PhantomReference。该文档只说一个幻影可到达对象会保留下来,这是未清除的结果,但没有解释为什么这有任何意义。

这个问题是brought up on SO,但答案并不令人满意。它说:“允许在清理对象之前执行清理”,这甚至可能与做出该设计决定的人的心态相符,但是由于清理代码无法访问该对象,因此是否执行该对象没有任何意义。回收对象之前或之后。如上所述,由于此规则取决于PhantomReference对象的可访问性(取决于可优化代码转换),因此甚至有可能在清理代码完成之前将对象与PhantomReference实例一起回收的情况下,没有人注意到。

我在2013年也发现了类似的question on the HotSpot developer mailing list,但也没有答案。

有一个增强请求JDK-8071507可以更改该行为并清除PhantomReference,就像其他请求一样,对于Java 9的状态为“已修复”,实际上its documentation现在声明已像其他任何引用一样将其清除。

不幸的是,这意味着我的帖子开头的答案从Java 9开始是错误的。然后,无论您是对new PhantomReference(new Object(), null)实例的强引用还是对Object实例的强引用,PhantomReference都会使新创建的ojit_code实例立即可以进行垃圾回收。不。

10-05 21:42