Java虚拟机通过可达性分析等算法探测堆中不可达的对象,当一个对象通过可达性算法不可达时,并非立即被回收,而是暂时处于在“缓刑”状态,而真正要宣告一个对象死亡,必须经历至少2次标记过程
——如果对象在进行可达性分析后发现与GC Roots引用链不相连时,那么它会被第一次标记并且进行一次筛选,筛选的条件是此对象是否需要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机执行过,那么这2种情况都被视作没有必要执行。
——如果对象被判定需要执行finalize()方法,那么这个对象将会放置在一个F-Queue队列中,并在之后由虚拟机自动建立的,低优先级的Finalizer线程去执行队列中的finalize()方法。
——执行指的是虚拟机会触发对象的finalize()方法,但不承若等待它运行结束。这样做的目的是:一来对象可能在finalize()方法中执行缓慢,而来方法可能出现死循环,将会导致F-Queue队列中其它对象永远处于等待状态。导致整个内存分配体系崩溃
——finalize()方法是对象逃脱被GC回收的最后一次机会,之后GC对F-Queue中的对象进行第二次标记,如果对象在finalize()中成功自救(只要重新与GC Roots引用链关联,如把自己赋值给某个类变量或对象的成员变量,那么第二次标记时将移出回收集合)
如果这个对象没有逃脱,那么将会被GC回收
实例演示:
创建一个类,重写finalize方法 在方法内重新将对象引用到一个变量中
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK=null;
public void isAlive()
{
System.out.println("still alive");
}
//重写finalize方法 使得本对象重新被变量引用
@Override
protected void finalize()throws Throwable
{
super.finalize();
System.out.println("finalize method execute");
FinalizeEscapeGC.SAVE_HOOK=this;
}
public static void main(String[] args) throws Throwable{
System.out.println("test");
// TODO Auto-generated method stub
SAVE_HOOK=new FinalizeEscapeGC();
//对象第一次自救
SAVE_HOOK=null;
System.gc();
//finalize处于低优先级执行队列中
Thread.sleep(500);
if(SAVE_HOOK!=null)
SAVE_HOOK.isAlive();
else
{
System.out.println("is dead");
}
//以下代码重复执行 但是自救失败
SAVE_HOOK=null;
System.gc();
//finalize处于低优先级执行队列中
Thread.sleep(500);
if(SAVE_HOOK!=null)
SAVE_HOOK.isAlive();
else
{
System.out.println("is dead");
}
}
}
运行结果:
第一次自救成功,第二次却失败了 因为对象的fianlize方法只会被执行一次
finalize()方法是一个代价很高的函数,不确定性大,无法保证各个对象的执行调用顺序,
所以任何情况下都不推荐使用finalize()方法