带有空队列的 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 PhantomReference
s 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
实例的强引用。
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 PhantomReference
s 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
实例的强引用。