Can a PhantomReference stop its referent from memory reclamation?

457 Views Asked by At

My question that sums it all up:

  • Can a strongly reachable Java PhantomReference stop its referent object's memory from being reclaimed by the Garbage Collector (GC)?

Details follow:

Callum posted this question as well but it is not answered straightforwardly. One response there refers to an article by Ethan Nicholas which seems to answer my question with a "No" but I'm not sure that is correct.

Based on my reading of the Java API I would have to answer my question with "Yes":

  • As long as PhantomReference.clear() is not called, and the PhantomReference instance itself is still strongly referred to, the referent object's memory will never be reclaimed and the referent will remain in a phantom reachable state.

To support this understanding I will quote the Java Docs:

  • "Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable."

For example, let's say I make a phantom reference and keep that instance in a List of PhantomReference. Then its referent falls from strongly reachable to phantom reachable.

If you take a look at com.google.common.base.internal.Finalizer.java, you will see the following code:

  private void cleanUp(Reference reference) throws ShutDown {
      ...

      /*
       * This is for the benefit of phantom references. Weak and soft
       * references will have already been cleared by this point.
       */
      reference.clear();

      ...
  }

I would prefer someone who is experienced with the subject to respond rather than doing a web search and providing me with links. Thanks!

1

There are 1 best solutions below

3
On BEST ANSWER

You mixed two things up. The linked question is not about the referent, but the PhantomReference instance. A PhantomReference instance, like all reference objects, can get garbage collected like any other object as long as it has not been enqueued. This is specified in the package specification:

The relationship between a registered reference object and its queue is one-sided. That is, a queue does not keep track of the references that are registered with it. If a registered reference becomes unreachable itself, then it will never be enqueued. It is the responsibility of the program using reference objects to ensure that the objects remain reachable for as long as the program is interested in their referents.

But your question is about the referent. Also, the cited code is about dealing with references which were already enqueued and even retrieved from the queue.

At this place, the documentation you’ve cited applies. Up to and including Java 8, referents of reachable PhantomReferences are not automatically cleared, so the referent stays phantom reachable until either, the reference is cleared or becomes unreachable itself. So the cited code is correct in clearing the reference explicitly to allow early reclaiming, though, the difference only affects the duration of the cleanup method’s execution, as afterwards, the PhantomReference likely becomes unreachable itself.


But that’s not the end of the story. There is no clear reason why referents should stay phantom reachable instead of being reclaimed. After all, the cleanup method can’t access the referent anyway.

So Java 9 drops that rule and clears phantom references automatically like any other reference. So starting with Java 9, manual clearing already enqueued phantom references is unnecessary, but of course, doesn’t hurt, so old software will still work smoothly.


Regarding you example:

…let's say I make a phantom reference and keep that instance in a List of PhantomReference. Then its referent falls from strongly reachable to phantom reachable.

Being the referent of a PhantomReference reference alone is not sufficient to be phantom reachable. It also requires that there are no strong references and the object has been finalized, though finalization is practically skipped for most objects, as they don’t have a custom finalize() method. When there are soft references additionally to the phantom reference, it may depend on the configuration and memory needs, whether the referent will become phantom reachable.