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 ...");
        }
    }
}
Tags:

Add a Comment

电子邮件地址不会被公开。 必填项已用*标注