javagarbage-collectionfinalizefinalizationphantom-reference

PhantomReference with null queue


Java allow to write:

new PhantomReference(new Object(), null)

At this case new Object() will be collected?

As I understand, phantom reference is alternative of finalize() method usage.

And after appearing reference in queue, I need to do some additional actions and then run clear()

java doc stays:

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?

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

which case correct?


Solution

  • 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.

    Since the PhantomReference without a queue will never be enqueued and its get() method will always return null, it is indeed not useful.

    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.


    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.

    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.

    I also found a similar question on the HotSpot developer mailing list back in 2013 which also lacks an answer.

    There is the enhancement request 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 now states that they are cleared like any other reference.

    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.