JAVA 虛擬機器 GC演算法和GC回收器
本章內容
- 標記-清除演算法
- 複製演算法
- 標記-整理演算法
- 分代收集演算法
- 七種垃圾收集器
標記-清除演算法
標記;遍歷所有的GC Roots,然後將所有GC Roots可達的物件標記為存活的物件
清除:清除的過程將遍歷堆中所有的物件,將沒有標記的物件全部清除掉
不足
1 效率問題 標記和清除兩個過程的效率都不高(都需要遍歷堆中所有的物件)
2 空間問題 標記清除之後會產生大量不連續的記憶體碎片,空間碎片太多可能會導致以後再程式執行過程中需要分配較大物件時,無法找到足夠的連續記憶體而不得不提前觸發另一次垃圾收集動作
複製演算法(解決效率問題)
將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊,當一塊的記憶體用完了,就將還存活的物件複製到另外一塊上面,然後再把已使用的記憶體空間一次清理掉(每次對半區進行記憶體回收)
不足
將記憶體縮小為了原來的一半
標記-整理演算法
標記:遍歷所有的GC Roots,然後將所有GC Roots可達的物件標記為存活的物件
整理:將所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體
分代收集演算法
根據物件的存活週期將記憶體劃分為幾塊,一般將Java堆分為新生代和老年代,這樣就可以根據各個年代的特點採用最合適的收集演算法
新生代 每次垃圾收集時都發現有大批物件死去,只有少量存活,那就選擇複製演算法,只需要付出少量存活物件的複製成本就可以完成收集
老年代 物件存活率高,沒有額外空間對它進行分配擔保,就必須使用標記-清理或標記-整理演算法來進行回收
七種垃圾收集器
Young 代表新生代收集器,Tenured 代表老年代收集器,如果兩個收集器之間存在聯絡,說明可以搭配使用
並行:指多條垃圾收集執行緒並行工作,但此時使用者執行緒仍然處於等待狀態
併發:指使用者執行緒與垃圾收集執行緒同時執行(但不一定是並行的,可能會交替執行),使用者程式在繼續執行,而垃圾收集程式運行於另一個CPU上
注意:目前的收集器收集過程均需要進行停頓(但是因記憶體回收而導致停頓的時間一直在縮短)
以下這些收集器的特性,基本原理和使用場景
Serial收集器(單執行緒)
在進行垃圾收集時,必須暫停其他所有的工作執行緒,直到它收集結束
虛擬機器執行在Client模式下的預設新生代收集器(簡單高效)
ParNew收集器(Serial多執行緒版本)
ParaLler Scavegne收集器(新生代收集器,使用複製演算法,並行的多執行緒收集器)
目標:達到一個可控制的吞吐量
吞吐量:CPU用於執行使用者程式碼的時間與CPU總消耗時間的比值,即吞吐量=執行使用者程式碼時間/(執行使用者程式碼時間 + 垃圾收集時間),虛擬機器總共運行了100min,其中垃圾收集花費1min,吞吐量即為99%
高吞吐量可以高效率地利用CPU時間,儘快完成程式的運算任務,主要適合在後臺運算而不需要太多互動的任務
Serial Old收集器
Seral收集器的老年代版本,單執行緒收集器,使用標記整理演算法
用途
1 是在JDK1.5以及之前的版本中與Parallel Scavenge收集器搭配使用
2 作為CMS收集器的後備預案,在併發收集發生Concurrent Mode Failure時使用
Parallel Old收集器
Parallel Scavenge收集器的老年代版本,使用多執行緒和標記整理演算法(Jdk1.6提供)
圖為:Parallel Scavenge和 ParallelOld搭配使用
CMS收集器(標記-清除演算法) 併發清除,低停頓
是一種以獲取最短回收停頓時間為目標的收集器
演算法過程(CMS收集器的記憶體回收過程是與使用者執行緒一起併發執行的)
1 初始標記(Stop The Word)標記一下GC Roots能直接關聯到的物件
2 併發標記 進行GC Root stracing(追蹤)的過程
3 重新標記(Stop The Word) 為了修正併發標記期間因使用者程式繼續運作而導致標記產生變動的那一部分物件的標記記錄,這個階段停頓時間一般會比初始標記階段稍長,但遠比並發標記的時間短
4 併發清除
缺點
1 對CPU資源非常敏感,在併發階段,雖然不會導致使用者執行緒停頓,但是會因為佔用了一部分執行緒而導致應用程式變慢,總吞吐量會降低(預設啟動的回收執行緒數是(CPU數量 + 3)/ 4)
2 CMS收集器無法處理浮動垃圾,可能出現Concurrent Mode Failure失敗而導致另一次Full GC的產生,由於CMS併發清理階段使用者執行緒還在執行著,伴隨著執行自然還會有新的垃圾不斷產生,這一部分垃圾出現在標記過程之後
3 使用的是標記-清除演算法,收集結束後會有大量空間碎片產生
G1收集器