天天看點

JVM-GC垃圾回收算法-引用計數法1原理2存在的問題

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);
}
           

其記憶體圖示如下

JVM-GC垃圾回收算法-引用計數法1原理2存在的問題

method方法中,執行完兩個set後,method方法結束,圖中兩條紅線引用消失,可以看到,留下兩個對象在堆記憶體中循環引用,但此時已經沒有地方在用他們了,造成記憶體洩漏。兩個對象就淩亂在風中不知所措了。

大家可以關注本人公衆号【Mr羽墨青衫】,會定期推送一些原創技術文章。

JVM-GC垃圾回收算法-引用計數法1原理2存在的問題