JVM垃圾回收機制(一)
阿新 • • 發佈:2019-01-31
一、什麼是垃圾?
1:引用計數演算法:給物件中加一個引用計數器,每當有一個引用指向它時,計數器的值就加一,引用失效時,計數器的值就減一。當該物件引用計數器等於0的時候就被視為垃圾。
該演算法存在很大的缺陷,若兩個物件存在互相引用,則兩者的引用計數器都不為0,都不能被GC。
如:
public class ReferenceCountingGC{
public Object instance = null;
public static void testGC(){
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
}
}
JVM顯然不會採用這種演算法。
2:可達性分析演算法:通過一系列的稱為“GC Roots”的物件作為起始點,從這些節點向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個物件從GC Roots不可達的時候,該物件則不可用,會被GC。
GC Roots包含:
- 虛擬機器棧(棧幀中的本地變量表)中引用的物件。
- 方法區中類靜態屬性引用的物件。
- 方法區中常量引用的物件。
- 本地方法棧中JNI(即Native方法)引用的物件。
二、垃圾收集演算法
1:標記清除演算法(Mark-Sweep):首先標記出所有需要回收的物件,在標記完成後統一回收。
該演算法的優缺點其實都很明顯:效率較高,但是標記清楚之後會產生大量不連續的記憶體碎片,導致以後如果有大物件需要分配時無法找到足夠大的連續記憶體空間,觸發另一次GC動作。
2:複製演算法(Copying):將可用的記憶體劃分為可用的兩塊,每次只使用其中一塊,當這一塊記憶體滿了之後,將這一塊當中存活的物件複製到另外一塊上去,再把原來的這一塊空間一次清理掉,這樣使得每次只對半個空間進行GC,簡單高效,代價是記憶體縮小為原來的一半。
3:標記整理演算法(Mark-compact):與標記清除演算法一樣,首先標記出所有需要回收的物件,然後再將所有存貨的物件都向一端移動,然後直接清理掉端邊界以外的記憶體。