我正在尝试使用ReferenceQueue释放由垃圾收集对象使用的资源。问题是,即使有证据证明所引用的对象之一已被垃圾回收,我的引用队列也始终为空。这是一个非常简单,自包含的JUnit测试,它说明了我正在尝试做的事情(跟踪对象的移除):

@Test
public void weakReferenceTest() {
    ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
    Object myObject1 = new Object();
    Object myObject2 = new Object();
    WeakReference<Object> ref1 = new WeakReference<Object>(myObject1, refQueue);
    WeakReference<Object> ref2 = new WeakReference<Object>(myObject2, refQueue);
    myObject1 = null;

    // simulate the application running and calling GC at some point
    System.gc();

    myObject1 = ref1.get();
    myObject2 = ref2.get();
    if (myObject1 != null) {
        System.out.println("Weak Reference to MyObject1 is still valid.");
        fail();
    } else {
        System.out.println("Weak Reference to MyObject1 has disappeared.");
    }
    if (myObject2 != null) {
        System.out.println("Weak Reference to MyObject2 is still valid.");
    } else {
        System.out.println("Weak Reference to MyObject2 has disappeared.");
        fail();
    }
    Reference<? extends Object> removedRef = refQueue.poll();
    boolean trackedRemoval = false;
    while (removedRef != null) {
        if (removedRef == ref1) {
            System.out.println("Reference Queue reported deletion of MyObject1.");
            trackedRemoval = true;
        } else if (removedRef == ref2) {
            System.out.println("Reference Queue reported deletion of MyObject2.");
            fail();
        }
        removedRef = refQueue.poll();
    }
    if (trackedRemoval == false) {
        fail();
    }
}


对我来说,这总是打印:

Weak Reference to MyObject1 has disappeared.
Weak Reference to MyObject2 is still valid.


...很好,但是由于trackedRemoval最后是false,因此测试始终失败-ReferenceQueue始终为空。

我在使用ReferenceQueue和/或WeakReference错误吗?我也尝试使用PhantomReference代替,但这没什么区别。

有趣的是,如果将单元测试转换为常规的public static void main(String[] args)方法,则它就像一个魅力!

谁能解释这个特定行为?我一直在寻找答案已经有一段时间了。

最佳答案

对我来说,这似乎是一种比赛条件。当GC确定myObject1引用的对象是GCable时,它将对其进行GC并从WeakReference中清除它。然后它将把WeakReference添加到“待处理的引用列表”中。有一个引用处理程序线程将从该列表中删除并添加到适当的ReferenceQueue中。以上是支持javadoc的实现细节


  在同一时间或以后,它将把那些
  通过参考注册的新清除的弱参考
  队列。


当代码到达时

Reference<? extends Object> removedRef = refQueue.poll();


引用处理程序线程必须未将WeakReference添加到ReferenceQueue中,因此poll返回null

关于java - 为什么ReferenceQueue始终为空?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25998367/

10-10 07:32