Non-Strong References in Java

I've always "sorta" known what a weak reference was in Java. I mean, it's common sense right? Sorta. I always figured it was a way to tackle the issue of circular references, but there is more to it than that. It turns out that there are actually 4 levels of references in Java: strong (implicit), soft, weak, and phantom, which the garbage collector (GC) handles in different ways.

The other day I encountered a SoftReference and wondered how it differs from WeakReference, so I decided to take a crash course on the subject; here is a nice (but long) article from Sun. Read on for my abridged version (teaching is the best way to learn, right?).

A strong reference is the default type and uses a counting mechanism to determine when it can be reclaimed by the garbage collector. When the counter hits zero, an object is reclaimed next time GC runs. Circular references mean that the counter will never hit zero, because none of the objects in the circle will be reclaimed first. The reason is that the GC doesn't determine when groups are no longer reachable, only individuals--this is how weak (actually soft, as you’ll soon see) references address the issue.

Encountering a SoftReference the other day is what made me question what I thought I knew about weak references. It turns out that a SoftReference is actually what I thought a WeakReference was. It is a reference that is held in memory until an OutOfMemory exception is about to be thrown, at which point the JVM must attempt to free softly referenced objects. SoftReferences are very useful for caches, because they allow a program to store things in memory that it can but would rather not recreate. For example, a web application that generates an image based hit counter could store the generated image data in memory using a SoftReference. Since the image can be recreated it’s no big deal if it’s lost, but since it costs (perhaps heavy) CPU time to regenerate, it would be beneficial to store it in memory as long as it has resources to do so.

A WeakReference is actually pretty useless for any kind of non-temporary storage. It works the same way as a SoftReference, except it is always reclaimed when the GC runs, rather than just when the system is out of memory. An interesting example that the article gives is to weakly reference a Thread object using a ReferenceQueue, which will notify the program when the Thread terminates (is no longer strongly reachable).

A PhantomReference is sort of tricky (I’ll have to work with it before I completely understand it), but it is an object that has been finalized, but not reclaimed. It becomes useful when used, in combination with ReferenceQueues to determine that an object has been reclaimed, to free up related resources (such as strong/soft references, etc).

For more info on ReferenceQueues, see the Sun article.