phantom reachable - An object is not strongly, softly, nor weakly reachable, has been determined to not be resurrectable by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run), and is reachable from the roots via one or more (uncleared) phantom reference objects. As soon as an object referenced by a phantom reference object becomes phantom reachable, the garbage collector will enqueue it. The garbage collector will never clear a phantom reference. All phantom references must be explicitly cleared by the program.
这段话说明了phantom reachable与strongly, softly, weakly reachable的区别,不好理解的话在“if it declares a finalize() method itself, then its finalizer will have been run“。
public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());
Object obj = null;
obj = queue.poll();
System.out.println(obj);
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ref.get());
obj = queue.poll();
System.out.println(obj);
}
}
class F{
}
先看上面这个例子,运行结果如下:
null
null
null
java.lang.ref.PhantomReference@10b30a7
这个结果正常,符合对PhantomReference的文档说明,PhantomReference引用的对象是unreachable的,即使未被垃圾回收器回收,通过get方法返回的也是空。接下来修改一下上面的实例:
public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());
Object obj = null;
obj = queue.poll();
System.out.println(obj);
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ref.get());
obj = queue.poll();
System.out.println(obj);
}
}
class F{
@Override
protected void finalize() throws Throwable {
System.out.println("======================");
super.finalize();
}
}
运行的结果:
null
null
======================
null
null
上一段代码唯一的区别就是F类重载了finalize方法,重载之后通过gc回收后,却没有加入到ReferenceQueue之中。然后再稍微修改上面的代码:
public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());
Object obj = null;
obj = queue.poll();
System.out.println(obj);
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc();//重新执行垃圾回收
System.out.println(ref.get());
obj = queue.poll();
System.out.println(obj);
}
}
class F{
@Override
protected void finalize() throws Throwable {
System.out.println("======================");
super.finalize();
}
}
这段代码的区别是在多执行了一次System.gc(),结果如下:
null
null
======================
null
java.lang.ref.PhantomReference@10b30a7
多执行一次System.gc()之后,就正常加入到了ReferenceQueue队列中了,其原因就是“if it declares a finalize() method itself, then its finalizer will have been run“,因为第一次执行GC的时候,F实例的状态为finalizable状态,即有finalize方法没有被执行。而第二次运行gc的时候,F实例的finalize方法已经执行完成,所以能正常加入ReferenceQueue。在第一段代码中,因为没有重载finalize的方法,java虚拟机会完成自动优化。其实这样做的目的是避免在finalize的方法中出现对象再生的情况。这个跟weakReference有着明显的区别,这一点也可以更可靠的监视一个对象是否被回收。