Java Refereces Example

There are four distinct forms of references in the JVM, and indeed many of these apply to other garbage collected languages.
  • Strong references
  • Soft references
  • Weak references
  • Phantom references
It's important to know the differences, what affect they have on the collector and when you should be using them.

Strong references

Strong references never get collected
package org.neverfear.leaks;
 
/*
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassStrong {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating strong references");
 
        // This is now a strong reference.
        // The object will only be collected if all references to it disappear.
        Referred strong = new Referred();
 
        // Attempt to claim a suggested reference.
        ClassStrong.collect();
 
        System.out.println("Removing reference");
        // The object may now be collected.
        strong = null;
        ClassStrong.collect();
 
        System.out.println("Done");
    }
 
}

Soft references

Soft references only get collected if the JVM absolutely needs the memory. This makes them excellent for implementing object cache's.
package org.neverfear.leaks;
 
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassSoft {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating soft references");
 
        // This is now a soft reference.
        // The object will be collected only if no strong references exist and the JVM really needs the memory.
        Referred strong = new Referred();
        SoftReference<Referred> soft = new SoftReference<Referred>(strong);
 
        // Attempt to claim a suggested reference.
        ClassSoft.collect();
 
        System.out.println("Removing reference");
        // The object may but highly likely wont be collected.
        strong = null;
        ClassSoft.collect();
 
        System.out.println("Consuming heap");
        try
        {
            // Create lots of objects on the heap
            List<ClassSoft> heap = new ArrayList<ClassSoft>(100000);
            while(true) {
                heap.add(new ClassSoft());
            }
        }
        catch (OutOfMemoryError e) {
            // The soft object should have been collected before this
            System.out.println("Out of memory error raised");
        }
 
        System.out.println("Done");
    }
 
}

Weak references

Weak references only get collected if no other object references it except the weak references. This makes them perfect for keeping meta data about a particular object for the life time of the object.
package org.neverfear.leaks;
 
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassWeak {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating weak references");
 
        // This is now a weak reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
        WeakReference<Referred> weak = new WeakReference<Referred>(strong);
 
        // Attempt to claim a suggested reference.
        ClassWeak.collect();
 
        System.out.println("Removing reference");
        // The object may be collected.
        strong = null;
        ClassWeak.collect();
 
        System.out.println("Done");
    }
 
}

Phantom references

Phantom references are objects that can be collected whenever the collector likes. The object reference is appended to a ReferenceQueue and you can use this to clean up after a collection. This is an alternative to the finalize() method and is slightly safer because the finalize() method may ressurect the object by creating new strong references. The PhantomReference however cleans up the object and enqueues the reference object to a ReferenceQueue that a class can use for clean up.
package org.neverfear.leaks;
 
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassPhantom {
 
    public static class Referred {
        // Note that if there is a finalize() method PhantomReference's don't get appended to a ReferenceQueue
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating phantom references");
 
        // The reference itself will be appended to the dead queue for clean up.
        ReferenceQueue dead = new ReferenceQueue(); 
 
        // This map is just a sample we might use to locate resources we need to clean up.
        Map<Reference,String> cleanUpMap = new HashMap<Reference,String>();
 
        // This is now a phantom reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
 
        PhantomReference<Referred> phantom = new PhantomReference(strong, dead);
        cleanUpMap.put(phantom, "You need to clean up some resources, such as me!");
 
        strong = null;
 
        // The object may now be collected
        ClassPhantom.collect();
 
        // Check for 
        Reference reference = dead.poll();
        if (reference != null) {
            System.out.println(cleanUpMap.remove(reference));
        }
        System.out.println("Done");
    }
 
}

ReferenceQueue

You saw me use the reference queue class in the previous example. A ReferenceQueue instance can be supplied as an argument to SoftReference, WeakReference or PhantomReference. When an object is collected the reference instance itself will be enqueued to the supplied ReferenceQueue. This allows you to perform clean up operations on the object. This is useful if you are implementing any container classes that you want to contain a Soft, Weak or Phantom reference and some associated data because you can get notified via the ReferenceQueue which Reference was just collected.

WeakHashMap class

There is also a convience WeakHashMap that wraps all keys by a weak reference. Allowing you to easily store meta data against an object and have the map entry including the meta data removed and collected when the original object itself is unreachable.
package org.neverfear.leaks;
 
import java.util.Map;
import java.util.WeakHashMap;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassWeakHashMap {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating weak references");
 
        // This is now a weak reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
        Map<Referred,String> metadata = new WeakHashMap<Referred,String>();
        metadata.put(strong, "WeakHashMap's make my world go around");
 
        // Attempt to claim a suggested reference.
        ClassWeakHashMap.collect();
        System.out.println("Still has metadata entry? " + (metadata.size() == 1));
        System.out.println("Removing reference");
        // The object may be collected.
        strong = null;
        ClassWeakHashMap.collect();
 
        System.out.println("Still has metadata entry? " + (metadata.size() == 1));
 
        System.out.println("Done");
    }
 
}

Java References

Java  References :

Releasing unused objects for garbage collection can be done efficiently using java weak reference. Yes. weak reference is related to garbage collection. In java we need to not anything explicitly for garbage collection (GC), this memory management overhead is taken care by java run-time itself.
Then what is the use of java weak reference? Let us see an example scenario, which will help us understand the problem in detail. Before that, we should be aware there are four types of references in java and they are strong reference, weak reference, soft reference and phantom reference.

Weak Reference

When there are one or more reference to an object it will not be garbage collected in Java. But this rule depends on what type of reference it is. If an object has only weak reference associated with other objects, then it is a valid candidate for garbage collection.
Let us take a sample scenario to understand it better. Let TextView be an object (recently programming in Android and so using its class for example :-)) and we will have program generated ids used for its identification. These ids are used in some other object for referencing the TextViews.
...
Map textViewIdMap = new HashMap();
textViewIdMap.put(textView1, iD1);
textViewIdMap.put(textView2, iD2)
...
Key is TextView object and value is the Id. Now, during the execution of the program we have removed a TextView object say textView1. We do not require that view object so we have made it null. Now, what will happen to the key-value pair(textView1, iD1) stored in HashMap. This pair as of now makes no sense and it is not required as that textview itself is null.
So, programmatic we need to ensure that, when a textView is removed then its corresponding entry in the map should be removed. Only then, that object becomes a candidate for garbage collection. Otherwise, even though it is not used at run-time, this stale object will not be garbage collected.

WeakHashMap

There is a predefined Map which uses weak reference. This is an implementation of Map interface and exactly same as HashMap but with only difference of weakrefernce. Key-value pairs extext WeakReference class.
...
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>
...
In WeakHashMap there is a private method name expungeStaleEntires(), which is used to remove stale entries as given in above scenario. This method is internally used before get/getEntry/put/resize/size /…. all methods. Only after expunge done the regular operation is done. It just makes a stale entry ‘null’ and releases it for garbage collection. You may read its source code for more detail.

Strong Reference vs Weak Reference

Strong reference is not something new, it is nothing but what we use in our daily programming. The default reference for objects. Strong reference is strongest of all references, if there there is a strong reference garbage collecter will not even come to this object :-)
StringBuilder iD1 = new StringBuilder();


WeakReference<TextView> weakTextView1 = new WeakReference<TextView>(textView1);

Types of References in Java

There are four types of references in Java,
  1. Strong Reference
  2. Soft Reference
  3. Weak Reference
  4. Phantom Reference
above is listed in the same order as their strength.
References

Soft Reference

Soft Reference is slightly stronger that weak reference. Soft reference allows for garbage collection, but begs the garbage collector to clear it only if there is no other option. That is, it is eligible for garbage collection, but garbage collector can remove it based on the memory crunch it has. If it is left with little memory and it is in a position to reclaim memory, then it will collect the soft references.

Phantom Reference

Phantom reference is different from soft/weak reference. This can never be reached before it is cleared in the program. Calling the get() on it return null always. When a phantom referenced object is garbage collected, it is notified via theReferenceQueue. We can use this to find when it is garbage collected and no use other than that.

Soft, weak and PhantomReference?


Phantom references can be used to perform pre-garbage collection actions such as freeing resources. Instead, people usually use the finalize() method for this which is not a good idea. Finalizers have a horrible impact on the performance of the garbage collector and can break data integrity of your application if you're not very careful since the "finalizer" is invoked in a random thread, at a random time. 

In the constructor of a phantom reference, you specify a ReferenceQueue where the phantom references are enqueued once the referenced objects becomes "phantom reachable". Phantom reachable means unreachable other than through the phantom reference. The initially confusing thing is that although the phantom reference continues to hold the referenced object in a private field (unlike soft or weak references), its getReference() method always returns null. This is so that you cannot make the object strongly reachable again. 

From time to time, you can poll the ReferenceQueue and check if there are any new PhantomReferences whose referenced objects have become phantom reachable. In order to be able to to anything useful, one can for example derive a class from java.lang.ref.PhantomReference that references resources that should be freed before garbage collection. The referenced object is only garbage collected once the phantom reference becomes unreachable itself.

import java.lang.ref.*;
import java.util.HashSet;
 
public class WeakReferenceTest {
    public static void main(String[] args) {
        ReferenceQueue queue = new ReferenceQueue();
        HashSet references = new HashSet();
        for (int i = 0; i < 500000; i++) {
            Integer integer = new Integer(i);
            references.add(new WeakReference(integer, queue));
 
            Reference reference;
            while ((reference = queue.poll()) != null) {
                references.remove(reference);
            }
        }
    }
}