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实例立即可以进行垃圾回收。不。