具有空队列的 PhantomReference
Java允许写:
new PhantomReference(new Object(), null)
这种情况下new Object()
会被收集吗?
At this case new Object()
will be collected?
据我了解,幻像引用是 finalize()
方法用法的替代方法.
As I understand, phantom reference is alternative of finalize()
method usage.
在队列中出现引用后,我需要做一些额外的操作,然后运行 clear()
And after appearing reference in queue, I need to do some additional actions and then run clear()
java 文档保留:
可以使用空队列创建幻像引用,但是这样的引用是完全没用的:它的 get 方法总是return null 并且,因为它没有队列,所以它永远不会入队
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
如果它永远不会入队是什么意思?
What does mean if it will never be enqueued?
据我了解,这意味着在完成方法调用后,引用不会添加到引用队列中.因此它可能导致:
1.对象内存会被一次性清空
2.对象内存不会被清除
As I understand it means that after finalize method invocation rerference will not be added to the referenceQueue. Thus it may lead to:
1. object memory will be cleared at once
2. Object memory will not be cleared
哪种情况正确?
推荐答案
好吧,正如您自己注意到的,PhantomReference
不会自动清除.这意味着只要您保持对 PhantomReference
的强引用,所指对象将保持虚可访问.正如 文档 所说:"通过幻像引用可访问的对象将保持不变,直到所有此类引用被清除或自身变得不可访问."
Well, as you noticed yourself, a PhantomReference
is not automatically cleared. This implies that as long as you keep a strong reference to the PhantomReference
, the referent will stay phantom reachable. As the documentation says: "An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable."
但是,考虑到对象何时不可访问(现在我说的是幻像引用本身")可能会导致许多意外.尤其是参考对象很可能不会提供有用的操作,随后将不会再被触及.
However, considering when an object is unreachable (now I’m talking about the "phantom references themselves") can lead to many surprises. Especially as it’s very likely that the reference object, not providing useful operations, will not be subsequently touched anymore.
由于没有队列的PhantomReference
永远不会入队,其get()
方法总是返回null
,确实没用.
Since the PhantomReference
without a queue will never be enqueued and its get()
method will always return null
, it is indeed not useful.
那么为什么构造函数允许构造这样一个无用的对象呢?好吧,第一个版本 (1.2) 的文档指出它将抛出 NullPointerException
如果队列为 null
.该声明一直持续到 1.4,然后 Java 5 是第一个版本,其中包含可以在没有队列的情况下构造 PhantomReference
的语句,尽管没用.我的猜测是,它总是继承了超类的允许 null
队列的行为,这与文档相矛盾,而且很晚才注意到,因此决定保持兼容并调整文档而不是而不是改变行为.
So why does the constructor allows to construct such a useless object? Well, 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 is the first version containing the statement that you can construct a PhantomReference
without a queue, despite being useless. My guess is, that it always inherited the super class’ behavior of allowing a null
queue, contradicting the documentation, and it was noticed so late, that the decision was made to stay compatible and adapt the documentation rather than changing the behavior.
这个问题,更难回答,是为什么 PhantomReference
不会自动清除.文档只说幻影可达对象将保持不变,这是未清除的结果,但没有解释为什么这有任何相关性.
The question, even harder to answer, is why a PhantomReference
isn’t automatically cleared. The documentation only says that a phantom reachable object will remain so, which is the consequence of not being cleared, but doesn’t explain why this has any relevance.
这个问题是在 SO 上提出的,但答案并不令人满意.它说允许在对象被垃圾回收之前执行清理",这甚至可能符合做出该设计决策的人的心态,但由于清理代码无法访问该对象,因此它没有相关性是在对象被回收之前还是之后执行.如上所述,由于该规则取决于 PhantomReference
对象的可达性,该对象需要优化代码转换,甚至可能会出现对象与 PhantomReference<一起被回收的情况/code> 清理代码完成之前的实例,没有人注意到.
This question has been brought up on SO, but the answer isn’t really satisfying. It says "to allow performing cleanup before an object is garbage collected", which might even match the mindset of whoever made that design decision, but since the cleanup code can’t access the object, it has no relevance whether it is executed before or after the object is reclaimed. As said above, since this rule depends on the reachability of the PhantomReference
object, which is subject to optimizing code transformations, it might be even the case that the object is reclaimed together with the PhantomReference
instance before the cleanup code completes, without anyone noticing.
我还发现了类似的问题早在 2013 年的 HotSpot 开发者邮件列表 也没有答案.
I also found a similar question on the HotSpot developer mailing list back in 2013 which also lacks an answer.
有增强请求 JDK-8071507 以更改该行为并清除PhantomReference
就像其他的一样,对于 Java 9 具有固定"状态,实际上,它的文档现在声明它们像任何其他参考一样被清除.
There is the enhancement request 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 now states that they are cleared like any other reference.
不幸的是,这意味着我的帖子开头的答案从 Java 9 开始是错误的.然后,new PhantomReference(new Object(), null)
将使新创建的 Object
实例立即符合垃圾回收条件,无论您是否保留对 PhantomReference
实例的强引用.
This, unfortunately implies that the answer at the beginning of my post will be wrong starting with Java 9. Then, new PhantomReference(new Object(), null)
will make the newly created Object
instance immediately eligible for garbage collection, regardless of whether you keep a strong reference to the PhantomReference
instance or not.
相关文章