2

演示代码:

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Object test = new Object();
        ReferenceQueue<Object> q = new ReferenceQueue<Object>();
        PhantomReference<Object> p = new PhantomReference<Object>(test, q);
        Object lock = new Object();
        while (true) {
            synchronized (lock) {
                                 //q.poll() is null always,why?
                if (q.poll() != null) {
                    break;
                }
                //System.gc();
                lock.wait();
            }
        }
        System.out.println(1111111);
    }
}

我测试了代码,但它总是死循环。代码 (System.out.println(1111111);) 无法执行,q.poll() reurn null。

我认为如果测试对象被 GC 删除,q.poll() 将返回 p 对象,然后中断循环,但调用此演示代码,这与我的想法不同

编辑:我修改了演示代码,它现在可以工作了。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Object test = new Object();
        ReferenceQueue<Object> q   = new ReferenceQueue<Object>();
        PhantomReference<Object> p = new PhantomReference<Object>(test, q);
        Object lock = new Object();
        while (true) {
            synchronized (lock) {
                if (q.poll() != null) {
                    break;
                }
                test = null; //it is important  
                System.gc();
                lock.wait(100);//should not lock.wait()
            }
        }
        System.out.println(1111111);
    }
}

正如某人所说,语句(test = null)是key.GC收集分配null的测试对象。

4

2 回答 2

4

变量仍然存在的事实test意味着 GC 永远不会收集它所引用的对象......我相信 JVM 不会收集局部变量所引用的任何内容,即使在其余部分中从未引用过局部变量方法。

(此外,目前尚不清楚您为什么lock.wait()在没有任何呼叫时使用lock.pulse()。)

这是对我有用的代码:

import java.lang.Thread;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Object test = new Object();
        ReferenceQueue<Object> q = new ReferenceQueue<Object>();
        PhantomReference<Object> p = new PhantomReference<Object>(test, q);
        Object lock = new Object();
        while (true) {
            System.out.println("Checking queue...");
            if (q.poll() != null) {
                break;
            }
            System.out.println("Still polling...");
            System.gc();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println("Interrupted!");
                break;
            }
            // Make the object garbage...
            test = null;
        }
        System.out.println("Finished.");
    }
}
于 2011-09-22T10:58:52.770 回答
1

尝试

test = null;

在您的 while 循环之前,以便测试对象有资格进行垃圾收集。

于 2011-09-22T10:59:13.350 回答