views:

261

answers:

3

Can someone explain the difference between the three Reference classes (or post a link to a nice explanation)? SoftReference > WeakReference > PhantomReference, but when would I use each one? Why is there a WeakHashMap but no SoftHashMap or PhantomHashMap?

And if I use the following code...

WeakReference<String> ref = new WeakReference<String>("Hello!");
if (ref != null) {                 // ref can get collected at any time...
    System.gc();                   // Let's assume ref gets collected here.
    System.out.println(ref.get()); // Now what?!
}

...what happens? Do I have to check if ref is null before every statement (this is wrong, but what should I do)? Sorry for the rapid-fire questions, but I'm having trouble understanding these Reference classes... Thanks!

+3  A: 

A link: http://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html

PhantomHashMap wouldn't work very well as get always returns null for phantom references.

Caches are difficult, so SoftHashMap might not work as well as you might think. However, I believe Google's collection library contains a general reference map implementation.

You should always check that get returns non-null. (Note, that not checking that the Reference reference itself is not-null.) In the case of interned strings it always will, but (as ever) don't try to be "clever" about it.

Tom Hawtin - tackline
+4  A: 

They are explained in detail in this article and summarized as follows:

A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.

A soft reference is exactly like a weak reference, except that it is less eager to throw away the object to which it refers. An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while.

A phantom reference is quite different than either SoftReference or WeakReference. Its grip on its object is so tenuous that you can't even retrieve the object -- its get() method always returns null. The only use for such a reference is keeping track of when it gets enqueued into a ReferenceQueue, as at that point you know the object to which it pointed is dead.


Why there is no SoftHashMap or PhantomHashMap is probably because there are no reasonable real world use cases for them. Often an entity cache like EHCache is recommended over this. However, in Guava Collections you can use MapMaker to create/simulate a SoftHashMap.


As to the given code example, the ref will never be null. The ref.get() however can return null whenever the reference hold is GC'ed.


See also:

BalusC
+4  A: 

The Java library documentation for the java.lang.ref package characterizes the decreasing strength of the three explicit reference types.

You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."

By contrast, use a WeakReference when you don't want to influence the referenced object's lifetime; you merely want to make a separate assertion about the referenced object, so long as it remains alive. The object's eligibility for collection is not influenced by the presence of bound WeakReferences. Something like a an external mapping from object instance to related property, where the property need only be recorded so long as the related object is alive, is a good use for WeakReferences and WeakHashMap.

The last one -- PhantomReference -- is harder to characterize. Like WeakReference, such a bound PhantomReference exerts no influence on the referenced object's lifetime. But unlike the other reference types, one can't even dereference a PhantomReference. In a sense, it doesn't point to the thing it points to, as far as callers can tell. It merely allows one to associate some related data with the referenced object -- data that can later be inspected and acted upon when the referenced object when the PhantomReference gets queued in its related ReferenceQueue. Normally one derives a type from PhantomReference and includes some additional data in that derived type. Unfortunately, there's some downcasting involved to make use of such a derived type.

In your example code, it's not the ref reference (or, if you prefer, "variable") that can be null. Rather, it's the value obtained by calling Reference#get() that may be null. If it is found to be null, you're too late; the referenced object is already on its way to being collected:

final String val = ref.get();
if (null != val)
{
  // "val" is now pinned strongly.
}
else
{
  // "val" is already ready to be collected.
}
seh