Java 常見的垃圾收集器有哪些
實際上,垃圾收集器(GC,Garbage Collector)是和具體 JVM 實現緊密相關的,不同廠商(IBM、Oracle),不同版本的 JVM,提供的選擇也不同。接下來,我來談談最主流的 Oracle JDK。
Serial GC,它是最古老的垃圾收集器,“Serial”體現在其收集工作是單執行緒的,並且在進行垃圾收集過程中,會進入臭名昭著的“Stop-The-World”狀態。當然,其單執行緒設計也意味著精簡的 GC 實現,無需維護複雜的資料結構,初始化也簡單,所以一直是 Client 模式下 JVM 的預設選項。
從年代的角度,通常將其老年代實現單獨稱作 Serial Old,它採用了標記 - 整理(Mark-Compact)演算法,區別於新生代的複製演算法。
Serial GC 的對應 JVM 引數是:
-XX:+UseSerialGC
ParNew GC,很明顯是個新生代 GC 實現,它實際是 Serial GC 的多執行緒版本,最常見的應用場景是配合老年代的 CMS GC 工作,下面是對應引數
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
CMS(Concurrent Mark Sweep) GC,基於標記 - 清除(Mark-Sweep)演算法,設計目標是儘量減少停頓時間,這一點對於 Web 等反應時間敏感的應用非常重要,一直到今天,仍然有很多系統使用 CMS GC。但是,CMS 採用的標記 - 清除演算法,存在著記憶體碎片化問題,所以難以避免在長時間執行等情況下發生 full GC,導致惡劣的停頓。另外,既然強調了併發(Concurrent),CMS 會佔用更多 CPU 資源,並和使用者執行緒爭搶。
Parrallel GC,在早期 JDK 8 等版本中,它是 server 模式 JVM 的預設 GC 選擇,也被稱作是吞吐量優先的 GC。它的演算法和 Serial GC 比較相似,儘管實現要複雜的多,其特點是新生代和老年代 GC 都是並行進行的,在常見的伺服器環境中更加高效。
開啟選項是:
-XX:+UseParallelGC
另外,Parallel GC 引入了開發者友好的配置項,我們可以直接設定暫停時間或吞吐量等目標,JVM 會自動進行適應性調整,例如下面引數:
-XX:MaxGCPauseMillis=value -XX:GCTimeRatio=N // GC 時間和使用者時間比例 = 1 / (N+1)
G1 GC 這是一種兼顧吞吐量和停頓時間的 GC 實現,是 Oracle JDK 9 以後的預設 GC 選項。G1 可以直觀的設定停頓時間的目標,相比於 CMS GC,G1 未必能做到 CMS 在最好情況下的延時停頓,但是最差情況要好很多。
G1 GC 仍然存在著年代的概念,但是其記憶體結構並不是簡單的條帶式劃分,而是類似棋盤的一個個 region。Region 之間是複製演算法,但整體上實際可看作是標記 - 整理(Mark-Compact)演算法,可以有效地避免記憶體碎片,尤其是當 Java 堆非常大的時候,G1 的優勢更加明顯。
G1 吞吐量和停頓表現都非常不錯,並且仍然在不斷地完善,與此同時 CMS 已經在 JDK 9 中被標記為廢棄(deprecated),所以 G1 GC 值得你深入掌握。