Understanding Weak References in Java
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. You create a weak reference like this:
WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
and then elsewhere in the code you can use
weakWidget.get() to get the actual
Widget object. Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that
weakWidget.get()suddenly starts returning
WeakHashMap works exactly like
HashMap, except that the keys (not the values!) are referred to using weak references. If a
WeakHashMap key becomes garbage, its entry is removed automatically. If you're following the standard convention of referring to your maps via the
Map interface, no other code needs to even be aware of the change and requires no changes other than the switch from
HashMap to a
Difference degrees of Weakness
- Soft references -
- Phantom references - A phantom reference is quite different than either
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.
PhantomReferencesare enqueued only when the object is physically removed from memory, and the
get()method always returns
nullspecifically to prevent you from being able to "resurrect" an almost-dead object. Uses:
- Phantom references allow you to determine exactly when an object was removed from memory. They are in fact the only way to determine that. This isn't generally that useful, but might come in handy in certain very specific circumstances like manipulating large images: if you know for sure that an image should be garbage collected, you can wait until it actually is before attempting to load the next image, and therefore make the dreaded
PhantomReferencesavoid a fundamental problem with finalization:
finalize()methods can "resurrect" objects by creating new strong references to them. Well, the problem is that an object which overrides
finalize()must now be determined to be garbage in at least two separate garbage collection cycles in order to be collected. When the first cycle determines that it is garbage, it becomes eligible for finalization. Because of the (slim, but unfortunately real) possibility that the object was "resurrected" during finalization, the garbage collector has to run again before the object can actually be removed. And because finalization might not have happened in a timely fashion, an arbitrary number of garbage collection cycles might have happened while the object was waiting for finalization. This can mean serious delays in actually cleaning up garbage objects, and is why you can get
OutOfMemoryErrorseven when most of the heap is garbage. With
PhantomReference, this situation is impossible -- when a
PhantomReferenceis enqueued, there is absolutely no way to get a pointer to the now-dead object (which is good, because it isn't in memory any longer). Because
PhantomReferencecannot be used to resurrect an object, the object can be instantly cleaned up during the first garbage collection cycle in which it is found to be phantomly reachable. You can then dispose whatever resources you need to at your convenience.
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.
SoftReferences aren't required to behave any differently than
WeakReferences, but in practice softly reachable objects are generally retained as long as memory is in plentiful supply. This makes them an excellent foundation for a cache for the use case of image caching described below for instance.
Suppose you have an application which has to work with user-supplied images. Naturally you want to cache these images, because loading them from disk is very expensive and you want to avoid the possibility of having two copies of the (potentially gigantic) image in memory at once.
Because an image cache is supposed to prevent us from reloading images when we don't absolutely need to, you will quickly realize that the cache should always contain a reference to any image which is already in memory. With ordinary strong references, though, that reference itself will force the image to remain in memory, which requires you (just as above) to somehow determine when the image is no longer needed in memory and remove it from the cache, so that it becomes eligible for garbage collection. Once again you are forced to duplicate the behavior of the garbage collector and manually determine whether or not an object should be in memory.