First
of all, lets see what a WeakReference is. A normal reference to an
object is a strong reference, e.g.:
List
list = new LinkedList();
list.add(1)
list
is a strong reference to a LinkedList
object. It prevents the garbage-collector from removing the
LinkedList from memory, as long as list
is in the current scope of executing Java program. Now, you can also
wrap it around a WeakReference:
WeakReference<List<Integer>>
-
list = new WeakReference<List<Integer>>
- (new
LinkedList<Integer>());
List myList = list.get();
myList.add(1);
You now have a WeakReference (list) to a LinkedList, and you can obtain the LinkedList using the WeakReference.get() method. The purpose of a WeakReference is to allow the garbage-collector to gc the referred object if necessary. Consider the code below:
WeakReference<List<Integer>>
list.get().add(1);-
list = new WeakReference
- <List<Integer>>(new
LinkedList());
int i = 0;
while (i < 10) {
System.gc();
i++;
if (list.get() == null) {
System.out.println("GC-ed at iteration " + i);
break;
}
}
On
my JVM, it prints out:
GC-ed
at iteration 1
That
is, the LinkedList has been garbage-collected after the first
System.gc()
call (note that this does not necessarily have to happen)! While this behaviour is not guaranteed, we have certainly shown
that WeakReferences allows the referred object to be
garbage-collected.
WeakHashMap
The
java.util.WeakHashMap
class is one of the least frequently used in the Collections package,
and it uses WeakReferences internally. It is meant to serve as a
caching map where the entries can be garbage-collected if the JVM is
running low on memory. It accomplishes this by weak referencing the
keys
in
the map, also called weak
keys.
For instance, if you have a WeakHashMap which maps Strings to
Integers:
String
key = new String("one");
Integer
value = new Integer(1);
WeakHashMap<String,Integer>
weakMap = new WeakHashMap<String,Integer>();
weakMap.put(key,
value);
key
= null;
value
= null;
If
there are no other references to key,
then map entry (key,
value)
can
(but non-necessarily) be garbage-collected the next time GC happens.
If that happens, the size of the WeakHashMap will reduce from 1 to 0,
and the object key
will be garbage-collected:
String
key = new
String("one");
Integer
value = new Integer(1);
WeakHashMap<String,Integer>
weakMap = new
WeakHashMap<String,Integer>();
weakMap.put(key,
value);
key = null;
int
i = 0;
while
(i < 100) {System.gc();
i++;
if (weakMap.size() == 0) {
System.out.println("GC-ed at iteration " + i);
break;
}
}
In
my JVM, weakMap
becomes empty at iteration 6. If there are no other references to the
object value,
it will be garbage-collected too.
One
important fact to know about the WeakHashMap is that the value
objects are held using strong references. Therefore, if you had
mistakenly wrote:
WeakHashMap<String,String>
weakMap = new WeakHashMap<String,String>();
weakMap.put(key,
key);The entry for key will never be garbage-collected, because key is also held as the value object using a strong reference. If you need to use the same object as the value, it is recommended that you wrap it around a WeakReference, like:
weakMap.put(key,
new WeakReference(key));
This way, there will be no strong references to key, allowing it to be garbage-collected.