1、先看一个对象finalize的顺序问题。
public class A { B b; public void finalize() { System.out.println("method A.finalize at " + System.nanoTime()); } } public class B { public void finalize() { System.out.println("method B.finalize at " + System.nanoTime()); } } A a = new A(); a.b = new B(); a = null; System.gc();按照 http://java.sun.com/developer/technicalArticles/javase/finalization/
2、对象再生及finalize只能执行一次
public class B { static B b; public void finalize() { System.out.println("method B.finalize"); b = this; } } B b = new B(); b = null; System.gc(); B.b = null; System.gc();对象b本来已经被置null,GC检查到后放入F queue,然后执行了finalize方法,但是执行finalize方法时该对象赋值给一个static变量,该对象又可达了,此之谓对象再生。
public class A { } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);分析,在GC运行时,检测到new A()生成的对象只有一个WeakReference引用着,所以决定回收它,首先clear WeakReference的referent,然后referent的状态为finalizable,同时或者一段时间后把WeakReference放入监听的ReferenceQueue中。
ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(new A(), queue); Assert.assertNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);貌似和WeakReference没有什么区别呀,别急,还是有个细微的区别的,SoftReference和WeakReference在GC对referent状态改变时,先clear SoftReference/WeakReference对referent的引用,对应的referent状态为Finalizable,只是可以放入F queue,然后把SoftReference/WeakReference放入ReferenceQueue。
public class A { static A a; public void finalize() { a = this; } } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);即使new A()出来的对象再生了,在queue中还是可以看到WeakReference。
ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(new A(), queue); Assert.assertNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); // 第一次gc System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNull(obj); A.a = null; // 第二次gc System.gc(); obj = queue.poll(); Assert.assertNotNull(obj);第一次gc后,由于new A()的对象再生了,所以queue是空的,因为对象没有销毁。
Q&A
Q1:有这样一个问题,为什么UT会Fail?不是说对象会重生吗,到底哪里有问题?
public class Test { static Test t; @Override protected void finalize() { System.out.println("finalize"); t = this; } } public void testFinalize() { Test t = new Test(); Assert.assertNotNull(t); t = null; System.gc(); Assert.assertNull(t); Assert.assertNotNull(Test.t); }A: 对象是会重生不错。
public void testFinalize() throws Exception { Test t = new Test(); Assert.assertNotNull(t); t = null; System.gc(); Assert.assertNull(t); // 有可能fail. Assert.assertNull(Test.t); // 等一下gc,让gc线程的对象重生执行完。 Thread.sleep(5000); // 有可能fail. Assert.assertNotNull(Test.t); }这个ut和上面那个大同小异。
// 有可能fail. Assert.assertNull(Test.t);嗯,测试通过。但是没有人确保它每次都通过。所以我两处的注释都声明有可能fail。
// 有可能fail. Assert.assertNull(Test.t);To luliruj and DLevin
public class Tem { public static void main(String[] args) throws Exception { ReferenceQueue queue = new ReferenceQueue(); // SoftReference ref = new SoftReference(new B(), queue); // WeakReference ref = new WeakReference(new B(), queue); PhantomReference ref = new PhantomReference(new B(), queue); while (true) { Object obj = queue.poll(); if (obj != null) { System.out.println("queue.poll at " + new Date() + " " + obj); break; } System.gc(); System.out.println("run once."); } Thread.sleep(100000); } } class B { @Override protected void finalize() throws Throwable { System.out.println("finalize at " + new Date()); } }
转载自:http://zhang-xzhi-xjtu.iteye.com/blog/413159,分享给大家!