说明,是拜读 <JVM高级特性与最佳实践> 以后的笔记而已,基本上只是做一个记录..
package com.taobao.jvm; public class FinalizeEscape { public static FinalizeEscape FC = null; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize method invoke"); FC = this; } public static void main(String[] args) throws Exception { FC = new FinalizeEscape(); FC = null; System.gc(); Thread.sleep(500); if(FC != null) System.out.println("i am alive"); else System.out.println("i am dead"); FC = null; System.gc(); Thread.sleep(500); if(FC != null) System.out.println("i am alive"); else System.out.println("i am dead"); } }
执行的结果是
解释:
1 很多教科书上说判断对象是否存活的算法是这样的:给对象添加一个引用计数器,当又一个地方引用他是,计数器+1.引用失效时,则-1.引用为0则回收..但是,其实这种引用计数算法并没有被JAVA采用..JAVA采用的是根搜索算法.
2 jvm在执行垃圾回收的时候会有两个步骤
(1)如果对象没有被引用,则进行第一次标记,然后还做另外一个操作,判断是否需要执行该对象的finalize方法.判断的条件是:该对象有没重写finalize方法.如果没有被重写,则不执行.如果该对象重写了finalize方法,但是已经被虚拟机调用过一次,则也不执行
如果该对象需要被执行finalize方法,则会被放入到一个低优先级队列中,虚拟机会自动开一个线程去执行这个队列.这也是为什么上面在system.gc后还要sleep 500毫秒的原因.
(2)GC会对在队列中对象记性二次标记,如果对象没有在finalize方法中拯救自己,则离死不远了.
3 有些人会怀疑
System.gc();
这个方法调用JVM的GC不保证一定能执行GC.这个我通过打印GC信息得到验证,至少在这个程序中,gc是保证被执行的.
[GC 317K->224K(60864K), 0.0006300 secs] [Full GC 224K->158K(60864K), 0.0040963 secs] finalize method invoke i am alive [GC 793K->190K(60864K), 0.0001947 secs] [Full GC 190K->158K(60864K), 0.0048994 secs] i am dead
4 作者说:finalize方法是JAVA刚诞生的时候对C/C++的一种妥协.所以,忘掉他吧..虽然他能给对象一个最后拯救自己的机会.