首页 > 代码库 > Java Reference Types

Java Reference Types

References

Java provides two different types/classes of Reference Objects: strong and weak. Weak Reference Objects can be further divided into soft and phantom.

Strong Reference

StringBuilder builder = new StringBuilder(); 

This is the default type/class of Reference Object, if not differently specified: builder is a strong Reference Object. This kind of reference makes the referenced object not eligible for GC. That is, whenever an object is referenced by a chain of strong Reference Objects, it cannot be garbage collected.

Weak Reference

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

Weak Reference Objects are not the default type/class of Reference Object and to be used they should be explicitly specified like in the above example. This kind of reference makes the reference object eligible for GC. That is, in case the only reference reachable for the StringBuilder object in memory is, actually, the weak reference, then the GC is allowed to garbage collect the StringBuilder object. When an object in memory is reachable only by Weak Reference Objects, it becomes automatically eligible for GC.

Soft Reference

Garbage collector can collect an object if only weak references are pointing towards it and they are eagerly collected, on the other hand Objects with SoftReference are collected when JVM absolutely needs memory.

Phantom Reference

Object which only has Phantom reference pointing them can be collected whenever Garbage Collector likes it.

Useful Classes

WeakHashMap

Hash table based implementation of the Map interface, with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

ReferenceQueue

If the garbage collector discovers an object that is weakly reachable, the following occurs:

  • The WeakReference object‘s referent field is set to null, thereby making it not refer to the heap object any longer. 
  • The heap object that had been referenced by the WeakReference is declared finalizable. 
  • The WeakReference object is added to its ReferenceQueue. Then the heap object‘s finalize() method is run and its memory freed. 

When creating non-strong reference objects we have the option of passing a reference queue as a part of the Reference constructor. As seen from the above explanation, this reference queue is a way for the GC to inform the program that a certain object is no longer reachable.

Example

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class Test {
     public static void main(String[] args) throws InterruptedException {
         SavePoint savePoint = new SavePoint("Random"); // a strong object

         ReferenceQueue<SavePoint> savepointQ = new ReferenceQueue<SavePoint>();// the ReferenceQueue
         WeakReference<SavePoint> savePointWRefernce = new WeakReference<SavePoint>(savePoint, savepointQ);

         System.out.println("SavePoint created as a weak ref " + savePointWRefernce);
         Runtime.getRuntime().gc();
         System.out.println("Any weak references in Q ? " + (savepointQ.poll() != null));
         savePoint = null; // the only strong reference has been removed. The heap
         // object is now only weakly reachable

         System.out.println("Now to call gc...");
         Runtime.getRuntime().gc(); // the object will be cleared here - finalize will be called.

         System.out.println("Any weak references in Q ? " + (savepointQ.remove() != null));
         System.out.println("Does the weak reference still hold the heap object ? " + (savePointWRefernce.get() != null));
         System.out.println("Is the weak reference added to the ReferenceQ  ? " + (savePointWRefernce.isEnqueued()));

     }
}

class SavePoint {
    public SavePoint(String value) {

    }
}

The program :

  1. Creates a strong reference and adds it to a Weak reference savePointWRefernce. The object in memory is now referenced by a strong reference and a weak reference - hence strongly reachable. 
  2. The first call to garbage collector will not clear our savepoint object as it is a strong reference. Hence the poll method of the referenceQ will return null. (poll method is non - blocking it checks and returns immediately.) 
  3. The savePoint reference variable is set to null. Our heap object is now referenced only by the weak reference - hence it is weakly reachable. 
  4. The second gc call will now locate the object, executes its finalize method and mark this object to be freed. Theobject is also added to the ReferenceQ. 
  5. A call to the remove method of the ReferenceQ will return the object. remove is a blocking method. it will wait till an object has been made available in the Queue. (poll method might not work as the recycling process is happening on a separate thread.)

As seen once the object was ready to be released it was added to the reference queue. So the reference queue is like a callback to our java program, telling us that a particular object is released from its reference and is not available to our code anymore.

As seen from above the Reference queue actually holds within it the WeakReference which lost its heap object to clean up. The WeakReference does not have any association to the memory object. The get call above returns null. Unlike with finalize when we can make the object alive again, with the ReferenceQ there is no way to reach the released java object. Reference Queues are just for References that got freed by garbage collection. They cannot be used to make alive our objects again. They can only be used to notify our code about the loss of memory objects referred to by these non- strong references.

 

Java Reference Types