每天資訊GC垃圾回收的原理和涉及的幾種演算法

菜單

GC垃圾回收的原理和涉及的幾種演算法

1 GC垃圾回收的原理

其實垃圾回收的原理很簡單:就是判斷出死亡的物件,然後清除死亡的,留下存活的即可。那麼怎麼判斷物件已經死亡呢?常有的有以下兩種:

1)

引用計數法(Reference Counting)

:在物件中新增一個引用計數器,每當一個地方引用它時,計數器就加1;當引用失效時,計數器就減1;

當引用計數為0時就會被回收

。但是它存在一個很大的問題就是迴圈引用:如下圖,當例項化A時,A會持有例項B,B會持有C,C持有A。這樣一來我們就會發現:如果需要回收A,除了釋放初始例項化引用,還需要釋放C的引用。但是由於ABC互相引用,所以就造成誰也無法釋放。主流的垃圾回收都沒有采用這種判斷方法,因為需要額外的工作來解決它(感興趣的童鞋可以看看智慧指標)。

GC垃圾回收的原理和涉及的幾種演算法

“”

2)可達性分析演算法(Reachability Analysis)

:在JAVA虛擬機器中就是透過可達性分析法來判定物件是否存活的。思路是透過“GC Roots”的物件(可以認為是確定固定存在的物件)作為起始點,然後從這些節點開始遍歷所有引用鏈,如果某個物件沒有GC Roots直接或間接的連線的話,這個物件(白色節點)就被認為程式中不再使用可以被回收了。如下圖:

GC垃圾回收的原理和涉及的幾種演算法

“”

2 垃圾回收的幾種演算法

標記清除:

其分為“標記”和“清除”兩個階段。首先標記出所有死亡的物件,然後把所有死亡的的物件進行清除操作。如下圖,我們可以清楚地看到,這種回收演算法有一個很大的問題:造成很多的不連續記憶體碎片,這樣一來,如果需要建立稍微大一點的物件,就很可能無法找到足夠大的記憶體空間。這就需要整個再進行一次標記整理來解決這一問題(耗時耗力)。

GC垃圾回收的原理和涉及的幾種演算法

“”

標記整理:

演算法分為”標記-整理-清除“階段,首先需要先標記出存活的物件,然後把他們整理到一邊,最後把存活邊界外的記憶體空間都清除一遍。這個演算法的好處就是不會產生記憶體碎片,但是由於整理階段移動了物件,所以需要更新物件的引用。

GC垃圾回收的原理和涉及的幾種演算法

“”

標記複製:

演算法分標記-複製兩個階段。首先會標記存活的物件,完成後,該演算法會把存活的物件都複製到一塊新的空記憶體裡去。最後將原來的記憶體空間清空。過程如下圖,這個演算法最大的問題就是需要很大的記憶體(實際用地,用於複製的記憶體空間),同時如果存活的物件非常多的話,標記和複製階段都就會很慢。同時也涉及到了物件位置改變需要更新引用。儘管看起來問題很大,但是根據分代理論:弱分代假說裡大多數物件生命週期短,這種情況下標記複製就很適合了(複製的存活物件少)。至於記憶體消耗太大的問題,java虛擬機器透過將新生代分為一個Eden區與2個Survivo區,其中一個Survivo區用來複制,這樣一來極大地提高了記憶體空間利用率。

GC垃圾回收的原理和涉及的幾種演算法

“”