Java:PhantomReference,ReferenceQueue和finalize

shr*_*000 5 java garbage-collection phantom-reference

我有PR,PR指向的对象O,以及为PR设置的RQ.我有一个线程继续轮询RQ,并在它在RQ中找到的第一个引用,线程打印它找到它的时间,然后退出.

事情很好,但是当O有一个finalize(无论多么微不足道)的时候,线程不再在RQ中找到引用并且无限期地继续运行.

问题:为什么会这样?我正在使用Sun JDK 1.6.

这是代码:

good case

public class MyGCPhantom 
{   
    public static void main(String[] args) throws InterruptedException 
    {       
        GCPhantomObject p = new GCPhantomObject();
        ReferenceQueue phantomQueue = new ReferenceQueue();
        PhantomReference<GCPhantomObject> pr = new PhantomReference<GCPhantomObject>(p, phantomQueue);      
        new GCPhantomThread(phantomQueue, "Phantom").start();
        p = null;

        System.gc();
    }
}

class GCPhantomObject
{   
    @Override
    protected void finalize()
    {
        //System.out.println("GCPhantom finalized " + System.currentTimeMillis());      
    }
}

class GCPhantomThread extends Thread
{
    private ReferenceQueue referenceQueue;
    private String name;

    GCPhantomThread(ReferenceQueue referenceQueue, String name)
    {
        this.referenceQueue = referenceQueue;
        this.name = name;
    }

    @Override
    public void run()
    {
        while(referenceQueue.poll() == null);       
        System.out.println(name + " found at " + System.currentTimeMillis());
    }
}
Run Code Online (Sandbox Code Playgroud)

bad case

刚刚取消对SOP中finalize()GCPhantomObject.

Mar*_*nik 4

你的分析有点不对劲。无论是好的情况还是坏的情况,您的对象都会实现finalize. 在好的情况下,它的实现是微不足道的;在好的情况下,它的实现是微不足道的。在糟糕的情况下,这并非易事。因此,明显的问题在于 的平凡实现和非平凡实现之间的区别finalize

我不明白为什么 JVM 会被规范强制将你的引用排队。您执行一次 GC 运行,然后继续等待某些事情发生。众所周知,任何重要的终结器都可能会复活该对象,因此在将其排队之前可能需要更多的 GC 周期。我建议添加更多 GC 调用。

另请注意,不建议您决定使用poll而不是。remove您应该使用阻塞调用来防止忙轮询。

作为参考,这些是文档中的相关定义:

如果垃圾收集器在某个时间点确定幻像引用的指示对象是幻像可达的,那么在那时或稍后的某个时间,它将将该引用排队。


如果一个对象既不是强可达性、软可达性也不是弱可达性,则该对象是幻可达的,并且该对象已被最终确定,并且某个虚引用引用了该对象。


已终结的对象已自动调用其终结器。