16

We can see that "phantom reachable" is as unreachable as "unreachable": §

An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.

Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.

Now, from: http://download.oracle.com/javase/6/docs/api/java/lang/ref/PhantomReference.html

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.

What's the underlying rationale? Is there even one?

Is this yet another typical case of Java API quirk?

Community
  • 1
  • 1
dsatish
  • 1,041
  • 15
  • 27

2 Answers2

7

Soft references are cleared when enqueued because the primary use of soft references are to allow caching of large objects, and clearing the soft references allows the large cached object to be garbage collected.

Weak references are cleared when enqueued because the primary use of weak references are to allow one to reference an object without preventing it from being garbage collected, so clearing the references as soon as the object is enqueued allows the object to be garbage collected.

Phantom references are not cleared when enqueued since one use case of phantom references is to allow performing cleanup before an object is garbage collected. By not clearing the references, the object remains phantomly reachable (and not eligible for garbage collected) until after the PhantomReference to that object is cleared by the user, or the PhantomReference is itself garbage collected.

This is explained here,

An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.

Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.

Community
  • 1
  • 1
sbridges
  • 24,960
  • 4
  • 64
  • 71
  • 1
    thanks for the answer. Do you know of a use case where phantom references are used? – dsatish Aug 15 '11 at 04:14
  • 5
    If a phantom reference has been created to an object but no other reference to it exists, by what means could an accessible reference to the object ever exist? And if no accessible reference could ever exist, why shouldn't the object be collected? – supercat Oct 24 '14 at 03:13
  • @sbridges, **Citation needed** for "*one use case of phantom references is to allow performing cleanup before an object is garbage collected*". Fact check: There is **no such use case**. Indeed, how would it even matter if cleanup is done before or after the "reference" is available when the "reference" is [impossible to detect](http://archive.is/XhNht#selection-1531.227-1531.247)? – Pacerier Sep 18 '17 at 04:21
  • There is such use case. It often has to do with cleaning up external resources which are not managed by Java. For example, when doing OpenGL in Java, you must (as always in OpenGL) destroy the OpenGL resources (textures,shaders,etc) to free GPU memory,handles,etc, by calling the various glDelete-functions. You could manually keep track of when an OpenGL-resource is needed (C++ style memory management) or you can use Phantom-references and destroy the resources when their Java-wrappers are no longer strongly reachable. That way you don't have to do C style memory management for OpenGL resources – DisplayName Nov 04 '17 at 14:52
  • 3
    Update: It seems that for Java 9 they have changed the behavior of phantom references. Before java 9, phantom-references used to be easier for this, since you had access to the object that was about to be garbage collected (it wasn't gc'ed before being enqueued and it could be accessed by the protected `referent` variable without resurrecting it). But it seems they have changed this in java 9, so that the referent object is now gc'ed before enqueuing. So wrt. my OpenGL example, you might as well use weak refs (might also be better, since weak refs are enqueued sooner than phantom references). – DisplayName Nov 04 '17 at 17:15
  • @Bjarke As of Java 8, `Reference#referent` is `private` rather than `protected`. Anyway, I don't understand how you could access it without resurrecting it??? I wonder what happens, if I access it via reflection. – maaartinus Mar 17 '18 at 00:44
  • @Bjarke you could never access the referent of a `PhantomReference`—its `get()` method always returns `null` and this always has been the case. Besides that, the intended goal of preventing the collection of the referent until the cleanup completed, was never guaranteed. See also the second half of [this answer](https://stackoverflow.com/a/41987600/2711488). – Holger Sep 10 '18 at 12:04
  • @maaartinus I experimented with that in the past and using `PhantomReference` and what is today called “deep Reflection”, I could resurrect objects (better than with a finalizer which can do this trick only once per object). I’m really glad that this issue has been closed, if only for the confusion this API design and incomplete reasoning has created… – Holger Sep 10 '18 at 12:06
  • Yeah, i remembered incorrectly - the `referent` field was never protected, it was always private. You could get to it by reflection, and i remember many sources recommended this (but i don't remember the details of resurrection behavior). About a year ago, i rewrote my OpenGL-resource cleanup routine, so that the objects does not themselves contain the info to destroy their resources, but they have a `Destroyer` object containing this info for them (with no reference back to the res-object). So when object X gets gc'ed its Destroyer is called. Works with weak/soft/phantom-refs+no hacks=>better – DisplayName Sep 13 '18 at 16:00
  • (Another common approach is to subclass the XxxReference class itself, and store the info needed for destruction there. (This could for example store the mapping from object to Destroyer)) – DisplayName Sep 13 '18 at 16:31
  • The only use I have found for PhantomReferences is to debug memory leaks. A PhantomReference can't be created without a ReferenceQueue, so I can watch objects as they become eligible for garbage collection. Consequently, the change made in Java 9 has no effect on this. – MiguelMunoz Sep 28 '21 at 02:54
  • If I ever needed to clean up resources when an object is finalized, I would subclass the PhantomReference, which is where I would put my references to those resources. My subclass would have a cleanUp() method, which could be called by the thread that watches the ReferenceQueue. This way, it wouldn't matter that I can't reach the referent. I haven't tried this, but I've used PhantomReferences, and I'm pretty sure it would work. And cleanUp() could be private, with the queue-watching code in a static block, for security. (The changes in Java 9 would not affect this mechanism.) – MiguelMunoz Sep 28 '21 at 03:13
6

This was changed in JDK 9. Now phantom references are cleared as soft and weak references do. And the corresponding paragraph was removed from the Javadoc.

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.

Naman
  • 27,789
  • 26
  • 218
  • 353
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • Indeed, phantom references while automatically cleared by the garbage collector as they are enqueued in jdk 9... – kangjianwei Oct 21 '18 at 14:12