2018-10-14
JVM GC 对象逃逸
GC 判断为垃圾对象一定会回收吗
在可达性分析算法中不可达的对象,也并非是“非死不可”的。
要真正结束一个对象,至少要经历两次标记过程:如果对象在没有与 GC Roots 相连接将会被标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize() 方法。当对象没有覆盖 finalize() 方法,或者 finalize() 方法已经被虚拟机调用过,这两种情况都视为“没有必要执行”(即意味着直接回收)。
如果这个对象被判定为有必要执行 finalize() 方法,那么这个对象将会放置在一个叫做 F-Queue 的队列之中,由一个 Finalizer 线程去执行,虚拟机会触发这个方法,但并不承诺会等待运行结束。这样做的原因是:如果一个对象在 finalize() 方法中执行缓慢,或者发生了死循环,将很可能会导致 F-Queue 队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。
finalize() 方法是对象逃脱死亡的最后一次机会,只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this 关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时将被移除出“即将回收”的集合,否则这个对象就真的被回收了,此时称为对象逃逸。当该对象的引用关系撤销后,再次GC时,该对象将被直接回收。
对象逃逸只有一次机会,因为 finalize() 在整个对象的生命周期中,只会被执行一次。
public class EscapeGC {
public static EscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("I am still Alive");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize excute ...");
SAVE_HOOK = this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new EscapeGC();
deleteObject();
}
public static void deleteObject() throws InterruptedException {
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if(SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("Object is Dead ...");
}
}
}