GC执行finalize的过程以及对象的一次自我拯救
参考资料:深入理解java虚拟机
1 /** 2 * 此代码演示了两点: 3 * 1.对象可以在被GC时自我拯救 4 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法只会被系统自动调一次 5 */ 6 public class GC { 7 8 public static GC SAVE_HOOK = null; 9 10 public static void main(String[] args) throws InterruptedException { 11 SAVE_HOOK = new GC(); 12 //对象第一次拯救自己,并且成功了 13 SAVE_HOOK = null; 14 System.gc(); 15 //因为GC执行finalize方法的优先级很低,所以暂停一会 16 Thread.sleep(500); 17 if (null != SAVE_HOOK) { 18 //这句话输出了 19 System.out.println("Yes , I am still alive"); 20 } else { 21 System.out.println("No , I am dead"); 22 } 23 //第二次拯救自己,失败了 24 SAVE_HOOK = null; 25 System.gc(); 26 Thread.sleep(500); 27 if (null != SAVE_HOOK) { 28 System.out.println("Yes , I am still alive"); 29 } else { 30 //因为一个对象的finalize方法只会被调用一次 31 System.out.println("No , I am dead"); 32 } 33 } 34 35 @Override 36 protected void finalize() throws Throwable { 37 super.finalize(); 38 System.out.println("execute method finalize()"); 39 SAVE_HOOK = this; 40 } 41 }
当jvm利用可达性分析算法检测到一个对象不可达时,jvm并不会立即回收该对象,要经过两次标记。
第一次标记,如果该对象没有覆盖finalize方法,或者该对象的finalize方法已经执行过,则立即将其回收,不经过二次标记;
第二次标记,jvm会把该对象放到一个F-Queue的队列中,等待执行finalize方法(这里的执行是指jvm会触发这个方法,但并不会保证会等待它运行结束),如果该对象在finalize方法中重新与引用链上的任何一个对象建立关联,那么该对象重新复活;如果该对象在finalize方法中什么也不做,那么该对象仍然会被回收。