I’m on a memory management kick. Understanding how the Java runtime partitions memory, allocates space for objects, moves objects around, and performs garbage collection (see previous post) is a good base for our quest to writing memory conscious code. In this blog post I’ll describe Java’s four reference types, which you can use to assist the JVM in its memory management duties.
In order from strongest to weakest these references are: Strong, Soft, Weak, Phantom.
These are your regular object references:
Server server = new Server();
server holds a strong reference to a
Server object. OK, before you stop reading there is a point to this: objects that are reachable through any chain of strong references are not eligible for garbage collection. Usually this is what you want. But not always.
Imagine for a minute that you’re coding an Enterprise Web App backed by a large Oracle database. When users navigate your web app it loads data into memory from Oracle. Sometimes the same data is regularly accessed so you decide to cache it in a
Map. By storing strong references you’ve just introduced a memory leak. “Ha!”, you say, “then I’ll write a memory manager that throws out least frequently used objects when we begin to run out of memory”. But doesn’t the JVM already manage memory for you?
A weak reference will not pin an object into memory. An object that is identified as only weakly reachable will be collected at the next GC cycle.
WeakReference<Cacheable> weakData = new WeakReference<Cacheable>(data);
weakData.get(). This call to
get may return
null if the weak reference was garbage collected: you must check the returned value to avoid NPEs.
Java contains collections that use weak references. For example, the
<a href="http://docs.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html">WeakHashMap</a> class stores keys (not values) as weak references. If the key is GC’d then the value will automatically be removed from the map too.
Since weak references are objects too we need a way to clean them up (they’re no longer useful when the object they were referencing has been GC’d). If you pass a
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/ref/ReferenceQueue.html">ReferenceQueue</a> into the constructor for a weak reference then the garbage collector will append that weak reference to the
ReferenceQueue when it is no longer needed. You can periodically process this queue and deal with dead references.
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/ref/SoftReference.html">SoftReference</a> is like a weak reference but it is less likely to be garbage collected. Soft references are cleared at the discretion of the garbage collector in response to memory demand. The virtual machine guarantees that all soft references to softly-reachable objects will have been cleared before it would ever throw an
In practice these are rarely used.
Key point: phantom references are the most tenuous of all reference types: calling
get will always return
So how are they useful? When you construct a phantom reference you must always pass in a
ReferenceQueue. This indicates that you can use a phantom reference to see when your object is GC’d. The phantom reference is enqueued after it has been physically removed from memory — as opposed to weak references which are enqueued before they’re finalized or GC’d.
Hey, so if weak references are enqueued when they’re considered finalizable but not yet GC’d we could create a new strong reference to the object in the finalizer block and prevent the object being GC’d. Yep, you can but you probably shouldn’t do this. To check for this case the GC cycle will happen at least twice for each object, unless that object is reachable only by a phantom reference. This is why you can run out of heap even when it your memory contains plenty of garbage. Phantom references can prevent this.