Java虛擬機器-GC垃圾回收演算法-引用計數法

Mr羽墨青衫發表於2019-01-18

GC的出現解放了程式設計師需要手動回收記憶體的苦惱,但我們也是要了解GC的,知己知彼,百戰不殆嘛。 常見的GC回收演算法主要包括引用計數演算法、標記清除演算法、複製演算法、標記壓縮演算法、分代演算法以及分割槽演算法。

今天來聊聊引用計數演算法。

1原理

顧名思義,此種演算法會在每一個物件上記錄這個物件被引用的次數,只要有任何一個物件引用了次物件,這個物件的計數器就+1,取消對這個物件的引用時,計數器就-1。任何一個時刻,如果該物件的計數器為0,那麼這個物件就是可以回收的。

打個比方:

public static void method() {
    A a = new A();
}

public static void main(String[] args) {
    method();
}
複製程式碼

main函式呼叫method方法,method方法中new了一個A的物件,賦值給區域性變數a,此時堆記憶體中的物件A的例項的計數器就會+1。當方法結束時,區域性變數會隨之銷燬,堆記憶體中的物件的計數器就會-1。

2存在的問題

該演算法存在兩個問題:

(1)無法處理迴圈引用的情況。

(2)從上述的原理可知,堆內物件的每一次引用賦值和每一次引用清除,都伴隨著加減法的操作,會帶來一定的效能開銷。

所以Java沒有使用這種演算法來實現GC。

下面來解釋一下第一個問題,迴圈引用的情況。

即物件A引用物件B,物件B引用物件A。

考慮如下程式碼:

class A {
    private B b;
    public void setB(B b) {
        this.b = b;
    }
}

class B {
    private A a = new A();
    public void setA(A a) {
        this.a = a;
    }
}

public void method() {
    A a = new A();
    B b = new B();
    a.setB(b);
    b.setA(a);
}
複製程式碼

其記憶體圖示如下

Java虛擬機器-GC垃圾回收演算法-引用計數法
method方法中,執行完兩個set後,method方法結束,圖中兩條紅線引用消失,可以看到,留下兩個物件在堆記憶體中迴圈引用,但此時已經沒有地方在用他們了,造成記憶體洩漏。兩個物件就凌亂在風中不知所措了。


歡迎關注我的微信公眾號

公眾號

相關文章