带有空队列的 PhantomReference

PhantomReference with null queue

Java 允许写入:

new PhantomReference(new Object(), null)

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

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

在队列中出现参考后,我需要做一些额外的操作然后 运行 clear()

java 文档保持:

It is possible to create a phantom reference with a null queue, but such a reference is completely useless: Its get method will always return null and, since it does not have a queue, it will never be enqueued

永远不会排队是什么意思?

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

哪种情况正确?

好吧,正如您自己注意到的,PhantomReference 不会自动清除。这意味着只要您保持对 PhantomReference 的强引用,所指对象将保持虚可达。正如 documentation 所说:“通过幻象引用可访问的对象将一直存在,直到所有此类引用被清除或它们自身变得不可访问。

然而,考虑到对象何时无法访问(现在我说的是“幻影引用本身”)可能会导致许多意外。尤其是引用对象很可能不提供有用的操作,以后就不会再碰了。

因为没有队列的PhantomReference永远不会入队,它的get()方法总是returnnull,所以确实没用

那么为什么构造函数允许构造这样一个无用的对象呢?好吧,the documentation of the very first version (1.2) states that it will throw a NullPointerException if the queue is null. This statement persists until 1.4, then Java 5 是第一个版本,其中包含您 可以 构造一个没有队列的 PhantomReference,尽管它没有用。我的猜测是,它总是继承了允许 null 队列的超级 class' 行为,这与文档相矛盾,而且这么晚才注意到,因此决定保持兼容性并调整文档而不是改变行为。


更难回答的问题是为什么 PhantomReference 不会自动清除。文档只说幻影可达对象将保持不变,这是没有被清除的结果,但没有解释为什么这有任何关联。

这个问题已经 brought up on SO,但答案并不令人满意。它说“允许在对象被垃圾收集之前执行清理”,这甚至可能与做出该设计决定的人的心态相匹配,但由于清理代码无法访问该对象,它是在回收对象之前还是之后执行的都没有关系。如上所述,由于此规则取决于 PhantomReference 对象的可达性,该对象受优化代码转换的影响,因此甚至可能出现对象与 PhantomReference 实例一起回收的情况清理代码完成,没有人注意到。

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

有增强请求JDK-8071507 to change that behavior and clear PhantomReferences just like the others, which has the status “fixed” for Java 9, and indeed, its documentation现在声明它们像任何其他参考一样被清除。

不幸的是,这意味着我 post 开头的答案从 Java 9 开始是错误的。然后,new PhantomReference(new Object(), null) 将使新创建的 Object 实例立即符合垃圾回收条件,无论您是否保留对 PhantomReference 实例的强引用。