When Would You Use a Weakhashmap or a Weakreference

When would you use a WeakHashMap or a WeakReference?

One problem with strong references is
caching, particular with very large
structures like images. Suppose you
have an application which has to work
with user-supplied images, like the
web site design tool I work on.
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 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. You are forced to
duplicate the behavior of the garbage
collector and manually determine
whether or not an object should be in
memory.

Understanding Weak References, Ethan Nicholas

What is a WeakHashMap and when to use it?

Elements in a weak hashmap can be reclaimed by the garbage collector if there are no other strong references to the key object, this makes them useful for caches/lookup storage.

Weak reference are not restricted to these hash tables, you can use WeakReference for single objects. They are useful to save resource, you can keep a reference to something but allow it to be collected when nothing else references it. (BTW, a strong reference is a normal java reference). There are also weak references which tend not to be as readily collected as soft references (which don't tend to hang about for long after the last strong reference disappears)

When to use WeakReference?

WeakReference and SoftReference are used when you want to keep something around in case you need it again - but you might not need it and if you do need it you can recreate it.

For example if you have a Cache of information you've fetched from a website, you don't want to constantly re-fetch it but if you need memory you can always drop something you haven't used for a while and get it back again if you do need it.

SoftReferences in particular are useful for this sort of caching as it tells the GarbageCollector not to get rid of the objects unless it really needs to free up the memory.

WeakReference on the other hand the GC can clean up as soon as it likes.

I've used them before combined with a factory pattern. Keep a SoftReference to objects when you create them in the factory. If they are asked for again then return the already-created object. If they don't exist or have been garbage collected then create them, return them, and keep a SoftReference inside the factory.

Usage of WeakHashMap?

This is due to the fact that objects will be garbage collected (GCed) when they are no longer have a strong reference from any other part of the program.

Given a WeakHashMap<MyObject, String> then if we do the following:

MyObject mo = new MyObject();
map.put(mo, "Test");
mo = null;

Then the entry mo -> Test will be eligible for GC. This means that if you have a custom .equals implementation that uses some property of MyObject to test for equality then you cannot later do this:

MyObject mo2 = new MyObject();
map.get(mo2);

Because even though your overridden .equals method may say that mo2.equals(mo) == true it is not the case that mo2 == mo and therefore the entry may have already been GCed.

The point is that if you keep a reference to mo and use that to retrieve the value from the Map then it is the case that that reference must == mo and therefore two things are true:

  1. the entry mo -> Test cannot be gced
  2. you can use an == based .equals method to retrieve the entry from the map

Basically; as the GC will use strong references to test whether an object can be GCed it is best to ensure that your .equals method does the same to avoid confusion.

WeakHashMap and strongly referenced value

Reference queues are used to automatically remove entries.

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/ReferenceQueue.html

Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected.

Basically, weak references are a core part of the garbage collector, so when a GC sweep happens, unused references are found and put onto queues and then action can be taken based on the content of those queues.

A thread can sit on the queue's remove method to be alerted when cleanup needs to be done or poll the queue.

"Java theory and practice: Plugging memory leaks with weak references" explains:

The implementation of WeakHashMap illustrates a common idiom with weak references -- that some internal object extends WeakReference.

...

WeakHashMap uses weak references for holding map keys, which allows the key objects to be garbage collected when they are no longer used by the application, and the get() implementation can tell a live mapping from a dead one by whether WeakReference.get() returns null. But this is only half of what is needed to keep a Map's memory consumption from increasing throughout the lifetime of the application; something must also be done to prune the dead entries from the Map after the key object has been collected. Otherwise, the Map would simply fill up with entries corresponding to dead keys. And while this would be invisible to the application, it could still cause the application to run out of memory because the Map.Entry and value objects would not be collected, even if the key is.

...

Reference queues are the garbage collector's primary means of feeding back information to the application about object lifecycle. Weak references have two constructors: one takes only the referent as an argument and the other also takes a reference queue. When a weak reference has been created with an associated reference queue and the referent becomes a candidate for GC, the reference object (not the referent) is enqueued on the reference queue after the reference is cleared. The application can then retrieve the reference from the reference queue and learn that the referent has been collected so it can perform associated cleanup activities, such as expunging the entries for objects that have fallen out of a weak collection. (Reference queues offer the same dequeuing modes as BlockingQueue -- polled, timed blocking, and untimed blocking.)

EDIT:

Even with queues, weak maps can still leak. Ephemerons are an attempt to solve the case where a weak key references a strongly held value that references the key. They are not implementable in java.

Ephemerons solve a problem which is commonly found when trying to "attach" properties to objects by using a registry. When some property should be attached to an object, the property should (in terms of GC behavior) typically have the life-time that an instance variable of this object would have. However, this is complicated by having an external association between the object and its property such as:

property --------- registry --------- association --------- object

Here, the registry (a third party) will hold onto the association itself which would require manual removal from the registry (instead of automated garbage collection). While this problem can always be solved in any given concrete situation by using one of the various weak association types, choosing the 'right' kind of association depends on a variety of factors some of which can change dynamically.

Ephemerons solve this problem by defining that the 'contents' (value) of an ephemeron will be held strongly until the key is known to be garbage collected. From then on, the contents of the ephemeron will be held weakly. Therefore, the contents of an ephemeron can become eligible for garbage collection if and only if the key is garbage collectable which is the exact behavior which we would observe for an instance variable of the object.

What's the difference between SoftReference and WeakReference in Java?

From Understanding Weak References, by Ethan Nicholas:

Weak references

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 weakWidget = new WeakReference(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 null.

...

Soft references

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, such
as the image cache described above,
since you can let the garbage
collector worry about both how
reachable the objects are (a strongly
reachable object will never be removed
from the cache) and how badly it needs
the memory they are consuming.

And Peter Kessler added in a comment:

The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. One size does not fit all.



Related Topics



Leave a reply



Submit