java finalize逃脱_Java对象回收与finalize方法

生存还是死亡

事实上,即使被可达性分析算法判断为不可达,对象也不是“非死不可”,对象会先进入“缓刑”状态。要真正宣告一个对象死亡,至少要经历两次标记过程:

如果进行可达性分析后发现不存在任何从GC Roots到达对象的引用链,那么对象会被第一次标记并且进行进一步的筛选,筛选的条件是:对象是否有必要执行finalize()方法。若对象没有覆盖finalize()方法,或finalize()方法已经被虚拟机调用过,虚拟机认为对象没有必要执行finalize方法。

if(!可达性分析(对象)){

if(finalize方法执行必要性分析(对象)){

将对象加入F-Queue队列;

}else{

回收;

}

}

boolean 可达性分析(对象){

return 存在从GC Roots到对象的引用链 ? true : false;

}

boolean finalize方法执行必要性分析(对象){

return (对象覆盖了finalize方法 && finalize方法尚未被虚拟机调用) ? true : false;

}

如果对象被判定为“需要执行finalize()方法”,对象会被加入F-Queue队列。稍后一个由虚拟机自动创建的、低优先级的Finalizer线程将会逐个执行F-Queue队列中各个对象的finalize()方法。

需要注意,这里说的执行,指的是虚拟机会触发这个方法,但并不承诺会等待方法执行结束。这样做是为了防止某个对象的finalize()方法执行缓慢(甚至出现死循环),影响F-Queue队列中其他对象的finalize()方法的执行(甚至导致整个内存回收机制奔溃)。

finalize()方法是对象逃脱“死刑”的最后一次机会。GC将对F-Queue中的对象进行第二次标记,如果对象在finalize()方法中成功拯救自己——只要重新与引用链上任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时对象将被移出“死刑”名单;如果对象没有把握最后一次机会,那基本上它就要真的被“执行死刑”了。

下面来看一段代码:

public class FinalizeEscapeGC {

public static FinalizeEscapeGC SAVE_HOOK = null;

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println("finalize method executed!");

//自我拯救

FinalizeEscapeGC.SAVE_HOOK = this;

}

public static void main(String[] args) throws Exception{

SAVE_HOOK = new FinalizeEscapeGC();

SAVE_HOOK = null;

System.gc();

//因为finalize方法优先级很低,所以暂停0.5秒等待它

Thread.sleep(500);

if (SAVE_HOOK!=null){

System.out.println("yes, i am still alive...A");

}else {

System.out.println("no, i am dead...A");

}

SAVE_HOOK = null;

System.gc();

//因为finalize方法优先级很低,所以暂停0.5秒等待它

Thread.sleep(500);

if (SAVE_HOOK!=null){

System.out.println("yes, i am still alive...B");

}else {

System.out.println("no, i am dead...B");

}

}

}

main方法中,有两段几乎相同的代码,代码执行结果如下:

finalize method executed!

yes, i am still alive...A

no, i am dead...B

Process finished with exit code 0

第一段代码表明,对象成功结束finalize方法“逃脱死刑”;第二段代码表明,finalize方法并没有再次被调用。事实上,任何对象的finalize方法都只会被系统调用一次。

其实最好不要使用finalize方法,finalize方法不是C++里面的析构函数!finalize是Java诞生之初为了使C/C++程序员更容易接收它而做出的一个妥协。它的运行代价高昂,不确定性大,无法保证各个对象的调用顺序。finalize能做的所有工作,使用try-finally或者其他方式都可以做得更好、更及时。

《深入理解Java虚拟机》学习笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值