JVM 如何確定死亡物件?

roc_guo發表於2023-03-27
1.引用計數器演算法

引用計數演算法(Reference Counting) 屬於垃圾收集器的早期實現演算法了,它指的是在建立物件時關聯一個與之相對應的計數器,當此物件被使用時加 1,相反銷燬時 -1。當此計數器為 0 時,則表示此物件未使用,可以被垃圾收集器回收。

引用計數演算法的優缺點很明顯,其優點是垃圾回收比較及時,實時性比較高,只要物件計數器為 0,則可以直接進行回收操作;而缺點是無法解決迴圈引用的問題,比如以下程式碼:

public class RefCounterTest {
    // 物件 A
    static class RefObjectA {
        private RefObjectB refObjectB;
        public void setRefObjectB(RefObjectB refObjectB) {
            this.refObjectB = refObjectB;
        }
    }
    // 物件 B
    static class RefObjectB {
        private RefObjectA refObjectA;
        public void setRefObjectA(RefObjectA refObjectA) {
            this.refObjectA = refObjectA;
        }
    }
    // 測試程式碼
    public static void main(String[] args) {
        RefObjectA objectA = new RefObjectA();
        RefObjectB objectB = new RefObjectB();
        objectA.setRefObjectB(objectB);
        objectB.setRefObjectA(objectA);
        objectA = null;
        objectB = null;
    }
}

如以上程式碼所示,即使是將 main 方法中的 objectA 和 objectB 都設定為 null,也就是這兩個物件都徹底不使用了,但是因為二者存在相互引用的關係,所以它們所對應的物件計數器不為 0,這樣迴圈引用導致垃圾資料無法被清除的事件就產生了。

2.可達性分析演算法

可達性分析演算法(Reachability Analysis) 是目前主流虛擬機器中,使用最廣泛的判斷垃圾物件的實現演算法,它指的是從物件的起點(GC Roots)開始向下搜尋,如果物件到 GC Roots 沒有任何引用鏈相連時,也就是說此物件到 GC Roots 不可達時,則表示此物件可以被垃圾回收器所回收,如下圖所示:

JVM 如何確定死亡物件?JVM 如何確定死亡物件?

在 Java 語言中,可作為根節點(GC Roots)的物件有以下 4 類:
1. Java 虛擬機器棧中的引用物件,也就是 Java 虛擬機器棧幀中,本地變數表所儲存的(引用)物件。在 Java 虛擬機器棧幀中儲存的物件都是將來執行時,要使用的物件,所以和引用物件相關的物件都不能被回收;
2. 本地方法棧中的引用物件和 Java 虛擬機器棧中的引用物件類似,也不能被回收;
3. 方法區中類靜態屬性引用的物件也可以作為 GC Roots;
4. 方法區中常量引用的物件也可以作為 GC Roots。因為常量是儲存在常量池中的,屬於全域性可使用的物件,所以也能作為 GC Roots。

3.有關“引用”

不管是引用計數法還是可達性分析演算法都與物件的“引用”有關,這說明物件的引用決定了物件的生死,而 Java 中的引用也比較複雜,它從 JDK 1.2 之後,(引用)分成了以下 4 種型別:

1. 強引用:在程式碼中普遍存在的,類似 Object obj = new Object() 這類引用,只要強引用還在,垃圾收集器永遠不會回收掉被引用的物件;
2. 軟引用:是一種相對強引用弱化一些的引用,可以讓物件豁免一些垃圾收集,只有當 JVM 認為記憶體不足時,才會去試圖回收軟引用指向的物件,JVM 會確保在丟擲 OutOfMemoryError 之前,清理軟引用指向的物件;
3. 弱引用:非必需物件,但它的強度比軟引用更弱,被弱引用關聯的物件只能生存到下一次垃圾收集發生之前;
4. 虛引用:也稱為幽靈引用或幻影引用,是最弱的一種引用關係,無法透過虛引用來獲取一個物件例項,為物件設定虛引用的目的只有一個,就是當著個物件被收集器回收時收到一條系統通知。

總結

垃圾物件的判定有兩種常用的演算法:引用計數器演算法和可達性分析演算法。其中引用計數器演算法實現簡單、執行高效,但是存在迴圈引用的問題,所以主流的虛擬機器使用的都是可達性分析演算法,可達性分析演算法是從物件的根節點 GC Roots 向下搜尋,如果根節點相連就是正常的物件,否則為垃圾物件可以被垃圾回收器回收。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2941739/,如需轉載,請註明出處,否則將追究法律責任。

相關文章