Java允许写:
new PhantomReference(new Object(), null)
在这种情况下,会收集new Object()
吗?
据我了解,幻像引用是finalize()
方法用法的替代方法。
在队列中显示引用后,我需要执行一些其他操作,然后运行clear()
java doc stay:
可以使用空队列创建幻像引用,但是 这样的引用完全没用:它的get方法总是如此 返回null,因为它没有队列,所以永远不会 排队的
如果永远不会入队,意味着什么?
据我所知,这意味着在finalize方法调用之后,重新引用不会被添加到referenceQueue中。因此可能导致:
1.对象记忆将立即清除
2.不会清除对象内存
哪种情况正确?
答案 0 :(得分:4)
嗯,正如您自己注意到的那样,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
对象的可达性,这可能会优化代码转换,甚至可能是在{1}}实例之前将对象与PhantomReference
实例一起回收的情况。清理代码完成,没有人注意到。
我在2013年也发现了类似的question on the HotSpot developer mailing list,但也没有答案。
有一个增强请求JDK-8071507可以更改该行为,并清除PhantomReference
,就像其他人一样,其状态为“已修复”,现在为{9}} its documentation声明他们像任何其他参考一样被清除。
不幸的是,这意味着从Java 9开始,我的帖子开头的答案将是错误的。然后,new PhantomReference(new Object(), null)
将使新创建的Object
实例立即有资格进行垃圾回收,无论是否保留对PhantomReference
实例的强引用。