带有空队列的PhantomReference

时间:2016-12-30 12:10:16

标签: java garbage-collection finalization phantom-reference

Java允许写:

new PhantomReference(new Object(), null)

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

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

在队列中显示引用后,我需要执行一些其他操作,然后运行clear()

java doc stay:

  

可以使用空队列创建幻像引用,但是   这样的引用完全没用:它的get方法总是如此   返回null,因为它没有队列,所以永远不会   排队的

如果永远不会入队,意味着什么?

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

哪种情况正确?

1 个答案:

答案 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实例的强引用。