Search This Blog

Sunday 9 February 2014

Weak References in Java

I have been looking at the java.lang.ref package with a view to understanding references in java. It all started when I tried to understand WeakHashMap and its use in string pools. The various related terms mentioned totally flummoxed me and made some additional study essential. Below is a summary of my attempts at understanding.
Java objects in the memory are classified as:
  1. Strong References
  2. Soft References
  3. Weak References
  4. Phantom References
The most common type of objects in our programs are Strong References.
Objects which are associated with the code or are live are called strong references. Simply put "Any object that cannot be garbage collected is a strong reference."
Any program that we normally write runs entirely on strong references. However this does not mean that we can't use the other types.
Java also has a class of objects that can be treated as weak references.
Consider the below class:
public class SavePoint {
   private final String content;
   private Date actionTime;

   public SavePoint(String content) {
      this.content = content;
      this.actionTime = new Date();
   }

   @Override
   public String toString() {
      return SavePoint.class.getSimpleName() 
             + " [content : " + this.content + ", actionTime : " + this.actionTime;
   }
}
If I were to create an object of this class in my code, it would by default be a strong reference. But I can also use this class to create weak references.
SavePoint savePoint = new SavePoint("Hi"); // normally a strong Reference
// This is a weak reference
WeakReference<SavePoint> weakSavePoint = new WeakReference<SavePoint>(savePoint);
So what is a weak reference ? From wikipedia
a weak reference is a reference that does not protect the referenced 
object from collection by a garbage collector. Accordingly if GC were 
to run, then the object reference by weakSavePoint would be garbage 
collected. This collection is guaranteed as long as the actual object 
i.e. savePoint is not referred to by any strong reference.
Consider the below code:
public static void main(String[] args) {

      List<WeakReference<SavePoint>> savePoints = new ArrayList<WeakReference<SavePoint>>();
      WeakReference<List<WeakReference<SavePoint>>> weakList = new WeakReference<List<WeakReference<SavePoint>>>(
            savePoints);

      SavePoint savePoint = null;
      Set<SavePoint> savePointsToHold = new LinkedHashSet<SavePoint>();
      for (int i = 0; i < 5; i++) {
         savePoint = new SavePoint("This is savepoint No " + i);
         weakList.get().add(new WeakReference<SavePoint>(savePoint));
      }
      // the last savepoint is a strong reference
      savePointsToHold.add(savePoint);

      final Runtime RUNTIME = Runtime.getRuntime();
      System.out.println("total memory : " + RUNTIME.totalMemory() + ", free memory : " + RUNTIME.freeMemory());

      System.out.println("Now to call gc...");
      RUNTIME.gc();
      System.out.println("total memory : " + RUNTIME.totalMemory() + ", free memory : " + RUNTIME.freeMemory());
      for (int i = 0; i < 5; i++) {
         System.out.println("Value at location " + i + " is " + weakList.get().get(i).get());
      }

   }
In my code I have
  1. a list of weak references - a strong reference. This list has now been added to a WeakReference. 
  2. Once the list is not reachable from any point of my code it will be ready for garbage collection.
  3. For the elements inside the list, they are always reachable via the List (referred by variable weakList). However this list is also a weak reference. So if any of the list elements are not accessible from any strong reference they will be garbage collected.
On executing the code:
total memory : 61800448, free memory : 61153056
Now to call gc...
total memory : 61800448, free memory : 61228584
Value at location 0 is null
Value at location 1 is null
Value at location 2 is null
Value at location 3 is null
Value at location 4 is SavePoint [content : This is savepoint No 4, actionTime : Thu Oct 17 23:47:27 IST 2013
As seen after calling Runtime.gc(), the garbage collector cleared the list of weak references. Except for the last element - this element was a member of my set savePointsToHold. A strong reference. Hence it was not garbage collected. But all other weak references which were not referred to from any strong reference were garbage collected.
So what are soft references ? To be continued in the next post

3 comments:

  1. any object that cannot be garbage collected is a strong reference,
    So strong reference never garbage collected and we never face out of memory issue.
    Is it?

    ReplyDelete
  2. I mean if strong reference never garbage collected then Why GC concept?

    ReplyDelete
  3. Liked, but IMO you should make the distinction between objects (nodes in the graph traversed by GC) and references (edges)

    ReplyDelete