javareferencegarbage-collectionphantom-reference

Phantom reference not freed up during GC


I am slightly confused with the usage of phantom references. I read that when Object which only has Phantom reference pointing them can be collected whenever Garbage Collector likes it. But, it is not working as intended in my example.

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;


public class ClassTest {
    private static Thread m_collector;
    private static boolean m_stopped = false;
    private static final ReferenceQueue refque = new ReferenceQueue();
    Map<Reference,String> cleanUpMap = new HashMap<Reference,String>();


    public void startThread() {
        m_collector = new Thread() {
            public void run() {
                while (!m_stopped) {
                    try {
                            Reference ref = refque.remove(1000);
                            System.out.println(" Timeout ");
                                                if (null != ref) {
                            System.out.println(" ref not null ");

                        }
                    } catch (Exception ex) {
                        break;
                    }
                }
            }
        };
        m_collector.setDaemon(true);
        m_collector.start();
    }

    public void register() {
        System.out.println("Creating phantom references");

        class Referred {
                }

          Referred strong = new Referred();
          PhantomReference<Referred> pref = new PhantomReference(strong, refque);
    //    cleanUpMap.put(pref, "Free up resources");
          strong = null;

    }



public static void collect() throws InterruptedException {
    System.out.println("GC called");
    System.gc();
    System.out.println("Sleeping");
    Thread.sleep(5000);
}

public static void main(String args[]) throws InterruptedException {
    ClassTest test= new ClassTest();
    test.startThread();

    test.register();
    test.collect();
    m_stopped = true;
    System.out.println("Done");
}

}

In the above example when I run, I see that object "strong" is not garbage collected automatically. I expected that object will get garbage collected automatically when "strong" object is assigned to null. Strangely, it is garbage collected only when I uncomment the following line in the register function.

 //cleanUpMap.put(pref, "Free up resources");" 

What is the reason behind that? But, If I create phantom reference in the Main function itself, this problem doesn't occur. In other words, object is garbage collected automatically when "strong" is assigned to null inside the main function as in the following code.

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(); 

    PhantomReference<Referred> phantom = new PhantomReference(strong, dead);


    strong = null;

    // The object may now be collected
    System.out.println("Suggesting collection");
    System.gc();
    System.out.println("Sleeping");
    Thread.sleep(5000);

    // Check for 
    Reference reference = dead.poll();
    if (reference != null) {
        System.out.println("not null");
    }
    System.out.println("Done");
}  

Why is the behaviour different in both scenarios?


Solution

  • Your phantom reference is an ordinary Java object and it would be garbage collected if unreachable.

    If phantom reference is collected before or on the same collection as referenced object it would not be added to reference queue.

    Placing all phantom reference to a collection is preventing reference from being garbage collected prematurely.

    Normally you need dedicated collection of unprocessed phantom references along side with reference queue.

    You can find example of implementing phantom reference based post mortem clean up in this article.