Java對象死亡標記的過程

Java對象死亡標記的過程

在Java可達性標記算法中,要宣告一個對象死亡,至少要進行兩次標記過程

原理摘要

  • 首先,如果發現對象從GC root出發不可達,那麼就會被第一次標記並進行篩選。篩選條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法已經被執行過了,則會被判定爲“沒有必要執行”。
  • 在確定對象有必要執行finalize()方法後,它將會被放入一個隊列中,並由一個較低級別的線程去執行此方法。稍後GC會對此隊列進行第二次標記,如果發現依舊從GC roots不可達,那麼此對象基本上是要被真的回收了。
    • 也就是說,finalize()方法是對象逃脫死亡的最後一根稻草。如果對象可以在此方法中將自己建立起與GC roots 的可達性,也就是有其他人引用了此對象,那麼就可被免於清理
    • 注意:finalize只會被執行一次!

代碼驗證

class MyObject {
    public static MyObject sSaveHook;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize is executed!");
        sSaveHook = this;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        MyObject.sSaveHook = new MyObject();
        MyObject.sSaveHook = null;

        //======第一次GC======
        System.gc();
        Thread.sleep(500); // 由於finalize方法優先級較低,所有暫停主線程0.5秒以等待它的執行

        if(MyObject.sSaveHook != null){
            System.out.println("object is alive!"); //這是第一次的輸出結果
        } else {
            System.out.println("object is dead");
        }

        //======第二次GC======
        MyObject.sSaveHook = null;
        System.gc();
        Thread.sleep(500);

        if(MyObject.sSaveHook != null){
            System.out.println("object is alive!");
        } else {
            System.out.println("object is dead"); //這是第二次的輸出結果
        }
    }
}

第一次成功脫險,因爲調用finalize方法時這個對象重新找到了引用它的對象。第二次沒有,是因爲finalize方法只會被執行一次。也就說,第二次GC時沒有調用finalize方法,因此該對象對GC roots來說依舊不可達,結果被清除。

注意:由於實驗需要,筆者覆寫了finalize方法。但由於它的運行大家高昂,不確定性大,因此在實際應用中應避免finalize的使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章