Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weak references cleared atomically with placement on reference queue?

Tags:

Does the Java GC clear a weak reference atomically with placing the weak reference on the ReferenceQueue assigned to that reference? In other words, if a call to WeakReference.get() returns null, will the WeakReference be on the queue?

like image 571
Steve Brandli Avatar asked Jan 24 '18 20:01

Steve Brandli


1 Answers

Lets dissect Javadoc for WeakReference:

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable.

At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references.

At the same time it will declare all of the formerly weakly-reachable objects to be finalizable.

At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.

It looks like the steps are:

  1. Determine if object is weakly reachable.

  2. Clear that object from its WeakReference. WeakReference.get will return null.

  3. Mark that object finalizable.

  4. Right after or at some other time do enqueue the WeakReference into the queue (if WeakReference was created with a queue).

This means that even if WeakReference.get() returns null it is not guarantee that WeakReference.enqueue will be true or ReferenceQueue.poll wont return null.

See https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references for more.

Reference queues

Once a WeakReference starts returning null, the object it pointed to has become garbage and the WeakReference object is pretty much useless. This generally means that some sort of cleanup is required;WeakHashMap, for example, has to remove such defunct entries to avoid holding onto an ever-increasing number of deadWeakReferences.

The ReferenceQueue class makes it easy to keep track of dead references. If you pass a ReferenceQueueinto a weak reference's constructor, the reference object will be automatically inserted into the reference queue when the object to which it pointed becomes garbage. You can then, at some regular interval, process the ReferenceQueue and perform whatever cleanup is needed for dead references.

Sample code showing it:

    public static class A {
}

public  static void main(String[] args) throws Exception{
    A a = new A();

    ReferenceQueue<A> rq = new ReferenceQueue<A>();
    WeakReference<A> aref = new WeakReference<A>(a, rq);    
    a = null;

    //aref.get() should be a, aref.isEnqueued() should return false, rq.poll() should return null
    System.out.println( "0: " + aref + " : " + aref.get() + " : " + aref.isEnqueued() + "  " + rq.poll() ); 

    Thread.sleep(1000);

    System.out.println("Running GC.");
    Runtime.getRuntime().gc();  //let GC clear aref
    System.out.println("GC ran.");

    //aref.get() should be null, aref.isEnqueued() should return false, rq.poll() should return null
    System.out.println( "1: " + aref + " : " + aref.get() + " " + aref.isEnqueued() + "  " + rq.poll()  );   

    //give some time for GC to enqueue aref
    Thread.sleep(1000);

    //ref.get() should be null, aref.isEnqueued() should return true, rq.poll() should return aref
    System.out.println( "2: " + aref + " : " + aref.get() + " " + aref.isEnqueued() + "  " + rq.poll() );  
}
like image 156
tsolakp Avatar answered Sep 20 '22 13:09

tsolakp