Java GC期间未释放幻象引用

Java GC期间未释放幻象引用,java,reference,garbage-collection,phantom-reference,Java,Reference,Garbage Collection,Phantom Reference,我对幻影引用的用法有点困惑。我读到当只有幻影引用指向它们的对象可以在垃圾收集器喜欢的时候被收集时。但是,它并没有像我的示例中预期的那样工作 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

我对幻影引用的用法有点困惑。我读到当只有幻影引用指向它们的对象可以在垃圾收集器喜欢的时候被收集时。但是,它并没有像我的示例中预期的那样工作

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");
}

}
这背后的原因是什么?但是,如果我在主函数本身中创建幻影引用,这个问题就不会发生。换句话说,当在主函数内将“strong”赋值为null时,对象会自动被垃圾收集,如下代码所示

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");
}  
publicstaticvoidmain(字符串args[])抛出中断异常{
System.out.println(“创建幻像引用”);
//引用本身将附加到死队列以进行清理。
ReferenceQueue dead=新的ReferenceQueue();
幻影参考幻影=新幻影参考(强,死);
strong=null;
//现在可以收集该对象
System.out.println(“建议收集”);
gc();
System.out.println(“睡眠”);
睡眠(5000);
//查证
Reference=dead.poll();
如果(引用!=null){
System.out.println(“非空”);
}
系统输出打印项次(“完成”);
}  

为什么这两种情况下的行为不同?

您的幻影引用是一个普通的Java对象,如果无法访问,它将被垃圾收集

如果幻象引用是在被引用对象之前或在同一个集合上收集的,则不会将其添加到引用队列中

将所有幻影引用放置到集合可以防止引用被过早地垃圾收集

通常,您需要将未处理的幻影引用的专用集合与引用队列一起使用


您可以在中找到实现基于幻影引用的事后清理的示例。

您的幻影引用是一个普通Java对象,如果无法访问,它将被垃圾收集

如果幻象引用是在被引用对象之前或在同一个集合上收集的,则不会将其添加到引用队列中

将所有幻影引用放置到集合可以防止引用被过早地垃圾收集

通常,您需要将未处理的幻影引用的专用集合与引用队列一起使用

您可以在中找到实施基于幻影参考的验尸清理的示例。

可能重复的可能重复的
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");
}