Thursday, May 12, 2005

Soft references, Weak References, Phantom references in Java !!!

The Reference API in Java can leave any sane person fully confused !!!..I tried to make sense of what the different types of references are and what purpose do they solve.
I am still not crystal clear about the usability of all these references, but I hope I will understand someday.

Referent
An object that is softly, weakly, or phantomly referenced from inside a SoftReference, WeakReference, or PhantomReference object, respectively.

Soft references:
The garbage collector might or might not reclaim a softly reachable object depending on how recently the object was created or accessed, but is required to clear all soft references before throwing an OutOfMemoryError.

Weakly reachable objects are finalized some time after their weak references have been cleared. The only real difference between a soft reference and a weak reference is that the garbage collector uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.

Phantomly reachable objects are objects that have been finalized, but not reclaimed.
The garbage collector will never clear a phantom reference. All phantom references must be explicitly cleared by the program.

An excellent article explaining GC in Java is given at
http://www.artima.com/insidejvm/ed2/gc17.html

Excerpts from the article:
--------------------------
Note that whereas the garbage collector enqueues soft and weak reference objects when their referents are leaving the relevant reachability state, it enqueues phantom references when the referents are entering the relevant state. You can also see this difference in that the garbage collector clears soft and weak reference objects before enqueueing them, but not phantom reference objects. Thus, the garbage collector enqueues soft reference objects to indicate their referents have just left the softly reachable state. Likewise, the garbage collector enqueues weak reference objects to indicate their referents have just left the weakly reachable state. But the garbage collector enqueues phantom reference objects to indicate their referents have entered the phantom reachable state. Phantom reachable objects will remain phantom reachable until their reference objects are explicitly cleared by the program.

The garbage collector treats soft, weak, and phantom objects differently because each is intended to provide a different kind of service to the program. Soft references enable you to create in-memory caches that are sensitive to the overall memory needs of the program. Weak references enable you to create canonicalizing mappings, such as a hash table whose keys and values will be removed from the map if they become otherwise unreferenced by the program. Phantom references enable you to establish more flexible pre-mortem cleanup policies than are possible with finalizers

To use the referent of a soft or weak reference, you invoke get() on the reference object. If the reference hasn't been cleared, you'll get a strong reference to the referent, which you can then use in the usual way. If the reference has been cleared, you'll get null back. If you invoke get() on a phantom reference object, however, you'll always get null back, even if the reference object hasn't yet been cleared. Because the phantom reachable state is only attained after an object passes through the resurrectable state, a phantom reference object provides no way to access to its referent. Invoking get() on a phantom reference object always returns null, even if the phantom reference hasn't yet been cleared, because if it returned a strong reference to the phantom reachable object, it would in effect resurrect the object. Thus, once an object reaches phantom reachability, it cannot be resurrected.

Virtual machine implementations are required to clear soft references before throwing OutOfMemoryError, but are otherwise free to decide when or whether to clear them. Implementations are encouraged, however, to clear soft references only when the programs demand for memory exceeds the supply, to clear older soft references before newer ones, and to clear soft references that haven't been used recently before soft references that have been used recently.

Soft references enable you to cache in memory data that you can more slowly retrieve from an external source, such as a file, database, or network. So long as the virtual machine has enough memory to fit the softly referenced data on the heap together with all the strongly referenced data, the soft reference will in general be strong enough to keep the softly referenced data on the heap. If memory becomes scarce, however, the garbage collector may decide to clear the soft references and reclaim the space occupied by the softly referenced data. The next time the program needs to use that data, it will have to be reloaded from the external source. In the mean time, the virtual machine has more room to accommodate the strongly (and other softly) referenced memory needs of the program.

Weak references are similar to soft references, except that whereas the garbage collector is free to decide whether or not to clear soft references to softly reachable objects, it must clear weak references to weakly reachable objects as soon as it determines the objects are weakly reachable. Weak references enable you to create canonicalizing mappings from keys to values. The java.util.WeakHashMap class uses weak references to provide just such a canonicalizing mapping. You can add key-value pairs to a WeakHashMap instance via the put() method, just like you can to an instance of any class that implements java.util.Map. But inside the WeakHashMap, the key objects are held via weak reference objects that are associated with a reference queue. If the garbage collector determines that a key object is weakly reachable, it will clear and enqueue any weak reference objects that refer to the key object. The next time the WeakHashMap is accessed, it will poll the reference queue and extract all weak reference objects that the garbage collector put there. The WeakHashMap will then remove from its mapping any key-value pairs for keys whose weak reference object showed up in the queue. Thus, if you add a key-value pair to a WeakHashMap, it will remain there so long as the program doesn't explicitly remove it with the remove() method and the garbage collector doesn't determine that the key object is weakly reachable.

Phantom reachability indicates that an object is ready for reclamation. When the garbage collector determines that the referent of a phantom reference object is phantom reachable, it appends the phantom reference object to its associated reference queue. (Unlike soft and weak reference objects, which can optionally be created without associating them with a reference queue, phantom reference objects cannot be instantiated without associating the reference object with a reference queue.) You can use the arrival of a phantom reference in a reference queue to trigger some action that you wish to take at the end of an object's lifetime. Because you can't get a strong reference to a phantom reachable object (the get() method always returns null), you won't be able to take any action that requires you to have access to the instance variables of the target. Once you have finished the pre-mortem cleanup actions for a phantom reachable object, you must invoke clear() on the phantom reference objects that refer to it. Invoking clear() on a phantom reference object is the coup de gras for its referent, sending the referent from the phantom reachable state to its final resting place: unreachability.