这是我的代码
public class FinalizableObject {
@Override
protected void finalize() throws Throwable {
System.out.println("finalize() invoked for " + this);
super.finalize();
}
}
public class Main {
private static void test() throws InterruptedException {
ReferenceQueue<FinalizableObject> rq = new ReferenceQueue<FinalizableObject>();
FinalizableObject obj = new FinalizableObject();
PhantomReference<FinalizableObject> pr1 = new PhantomReference<FinalizableObject>(obj, rq);
obj = null;
System.gc();
Reference<? extends Object> ref = rq.remove();
System.out.print("remove " + ref + " from reference queue\n");
}
public static void main(String[] args) {
try {
test();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这很奇怪,rq.remove()将永远被阻止。为什么我的finalizable对象的幻像引用不能放入引用队列?它是否被GC收集?
答案 0 :(得分:1)
问题在于您的非平凡finalize()
方法。在默认实现中(在类Object
中),此方法实际上是空的。当其实现不为空时,则无法保证在调用finalize()
后立即收集对象。
如果您将以这种方式修改您的程序:
for (int i = 0; i < 1000; i++)
System.gc();
即。你会多次调用GC一次 - 它可能导致rq
对象被完全收集(在我的机器上测试)。
另外,我建议您按照以下链接进行探索:
UPD:另一种方式:您必须牢记,特殊的Finalizer-Thread会调用非平凡的finalize()
方法,这些方法也必须收集。因此,对于完整的pr
收集,您可以执行以下操作:
a)在Main
方法中创建标志:
public static volatile boolean flag;
b)在finalize()
方法中设置标志:
@Override
protected void finalize() throws Throwable {
System.out.println("finalize() invoked for " + this);
super.finalize();
Main.flag = true;
}
c)检查标志为true,然后再次呼叫gc()
:
System.gc();
while (!flag) Thread.sleep(10);
System.gc();