空队列的PhantomReference

gst*_*low 3 java garbage-collection phantom-reference finalization

Java允许编写:

new PhantomReference(new Object(), null)
Run Code Online (Sandbox Code Playgroud)

在这种情况下new Object()将被收集?

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

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

Java Doc保留:

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

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

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

哪种情况正确?

Hol*_*ger 6

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

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

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

那么为什么构造函数允许构造这样一个无用的对象呢?好吧,第一个版本(1.2)的文档指出,NullPointerException如果队列为,它将抛出a null。该语句一直持续到1.4,然后Java 5是第一个包含该语句的版本,尽管无用,您也可以PhantomReference无队列地构造a 。我的猜测是,它始终继承了超类的允许null队列的行为,与文档相矛盾,并且被发现太晚了,因此决定保持兼容性并改编文档,而不是更改行为。


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

SO提出了这个问题,但是答案并不令人满意。它说“允许对象被垃圾回收之前执行清理”,这甚至可能与做出设计决定的人的心态相符,但是由于清理代码无法访问该对象,因此它是在对象执行之前还是之后都没有关系。回收对象之后。如上所述,由于此规则取决于PhantomReference对象的可访问性,需要对对象进行可达性的优化代码转换,因此甚至有可能PhantomReference在清理代码完成之前将对象与实例一起回收,而没有任何人注意。

我在2013 年的HotSpot开发人员邮件列表中也找到了类似的问题,但也没有答案。

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

不幸的是,这意味着从Java 9开始,我帖子开头的答案将是错误的。然后,无论您是否强烈引用该实例new PhantomReference(new Object(), null),新创建的Object实例都将立即具有进行垃圾回收的资格PhantomReference