Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When would you use a WeakHashMap or a WeakReference?

People also ask

When should we use WeakHashMap?

WeakHashMap is an implementation of the Map interface that stores only weak references to its keys. Storing only weak references allows a key-value pair to be garbage-collected when its key is no longer referenced outside of the WeakHashMap. This class provides the easiest way to harness the power of weak references.

What is the use of WeakReference?

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings. Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable.

What's the difference between Softreference and WeakReference?

A Soft reference is eligible for collection by garbage collector, but probably won't be collected until its memory is needed. i.e. garbage collects before OutOfMemoryError . A Weak reference is a reference that does not protect a referenced object from collection by GC.

What is the difference between WeakHashMap and HashMap?

A WeakHashMap has key-value pairs i.e. it is quite similar to a HashMap in Java. A difference is that the WeakHashMap object that is specified as a key is still eligible for garbage collection. This means that the garbage collector has dominance over the WeakHashMap.


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


WeakReference versus SoftReference

One distinction to be clear on is the difference between a WeakReference and a SoftReference.

Basically a WeakReference will be GC-d by the JVM eagerly, once the referenced object has no hard references to it. A SoftReferenced object on the other hand, will tend to be left about by the garbage collector until it really needs to reclaim the memory.

A cache where the values are held inside WeakReferences would be pretty useless (in a WeakHashMap, it is the keys which are weakly referenced). SoftReferences are useful to wrap the values around when you want to implement a cache which can grow and shrink with the available memory.


One Common use of WeakReferences and WeakHashMaps in particular is for adding properties to objects. Occasionally you want to add some functionality or data to an object but subclassing and/or composition are not an option in that case the obvious thing to do would be to create a hashmap linking the object you want to extend to the property you want to add. then whenever you need the property you can just look it up in the map. However, if the objects you are adding properties to tend to get destroyed and created a lot, you can end up with a lot of old objects in your map taking up a lot of memory.

If you use a WeakHashMap instead the objects will leave your map as soon as they are no longer used by the rest of your program, which is the desired behavior.

I had to do this to add some data to java.awt.Component to get around a change in the JRE between 1.4.2 and 1.5, I could have fixed it by subclassing every component I was interested int (JButton, JFrame, JPanel....) but this was much easier with much less code.


Another useful case for WeakHashMap and WeakReference is a listener registry implementation.

When you create something which wants to listen to certain events, usually you register a listener, e.g.

manager.registerListener(myListenerImpl);

If the manager stores your listener with a WeakReference, that means you don't need to remove the register e.g. with a manager.removeListener(myListenerImpl) because it will be automatically removed once your listener or your component holding the listener becomes unavailable.

Of course you still can manually remove your listener, but if you don't or you forget it, it will not cause a memory leak, and it will not prevent your listener being garbage collected.

Where does WeakHashMap come into the picture?

The listener registry which whishes to store registered listeners as WeakReferences needs a collection to store these references. There is no WeakHashSet implementation in the standard Java library only a WeakHashMap but we can easily use the latter one to "implement" the functionality of the first one:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

With this listenerSet to register a new listener you just have to add it to the set, and even if it is not removed explicitly, if the listener is no longer referenced, it will be removed automatically by the JVM.


This blog post demonstrates the use of both classes: Java: synchronizing on an ID. The usage goes something like this:

private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();

public void performTask(String resourceId) {
    IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
    synchronized (mutext) {
        // look up the resource and do something with it
    }
}

IdMutextProvider provides id-based objects to synchronize on. The requirements are:

  • must return a reference to the same object for concurrent use of equivalent IDs
  • must return a different object for different IDs
  • no release mechanism (objects are not returned to the provider)
  • must not leak (unused objects are eligible for garbage collection)

This is achieved using an internal storage map of type:

WeakHashMap<Mutex, WeakReference<Mutex>>

The object is both key and value. When nothing external to the map has a hard reference to the object, it can be garbage collected. Values in the map are stored with hard references, so the value must be wrapped in a WeakReference to prevent a memory leak. This last point is covered in the javadoc.


If you for example want to keep track of all objects created of a certain class. To still allow these objects to be garbage collected, you keep a list/map of weak references to the objects instead of the objects themselves.

Now if someone could explain phantom-references to me, I'd be happy...


As stated above, weak reference are held for as long as a strong reference exists.

An example usage would be to use WeakReference inside listeners, so that the listeners are no longer active once the main reference to their target object is gone. Note that this does not mean the WeakReference is removed from the listeners list, cleaning up is still required but can be performed, for example, at scheduled times. This has also the effect of preventing the object listened to from holding strong references and eventually be a source of memory bloat. Example: Swing GUI components refering a model having a longer lifecycle than the window.

While playing with listeners as described above we rapidly realised that objects get collected "immediately" from a user's point of view.