Java面試進階27:垃圾收集器有哪些

Serial GC,它是最古老的垃圾收集器,“Serial”體現在其收集工作是單線程的,並且在進行垃圾收集過程中,會進入臭名昭著的“Stop-The-World”狀態。也意味簡單,所以一直是 Client 模式下 JVM 的默認選項。從年代的角度,通常將其老年代實現單獨稱作 Serial Old,它採用了標記 - 整理(Mark-Compact)算法,區別於新生代的複製算法。

ParNew GC,很明顯是個新生代 GC 實現,它實際是 Serial GC 的多線程版本,最常見的應用場景是配合老年代的 CMS GC 工作

CMS(Concurrent Mark Sweep) GC,基於標記 - 清除(Mark-Sweep)算法,設計目標是儘量減少停頓時間,這一點對於 Web 等反應時間敏感的應用非常重要,存在着內存碎片化問題,所以難以避免在長時間運行等情況下發生 full GC,導致惡劣的停頓

Parallel GC,在早期 JDK 8 等版本中,它是 server 模式 JVM 的默認 GC 選擇,也被稱作是吞吐量優先的 GC

G1 GC 這是一種兼顧吞吐量和停頓時間的 GC 實現,是 Oracle JDK 9 以後的默認 GC 選項。G1 可以直觀的設定停頓時間的目標,相比於 CMS GC,G1 未必能做到 CMS 在最好情況下的延時停頓,但是最差情況要好很多。G1 GC 仍然存在着年代的概念,但是其內存結構並不是簡單的條帶式劃分,而是類似棋盤的一個個 region。Region 之間是複製算法,但整體上實際可看作是標記 - 整理(Mark-Compact)算法,可以有效地避免內存碎片,尤其是當 Java 堆非常大的時候,G1 的優勢更加明顯。

 

垃圾收集的算法有哪些?

基本算法:

1)引用計數算法,很難處理循環引用關係。Python用但是Java不用

2)Java 選擇的可達性分析,將對象及其引用關係看作一個圖,選定活動的對象作爲 GC Roots,然後跟蹤引用鏈條,如果一個對象和 GC Roots 之間不可達,也就是不存在引用鏈條,那麼即可認爲是可回收對象。JVM 會把虛擬機棧和本地方法棧中正在引用的對象、靜態屬性引用的對象和常量,作爲 GC Roots。

常見的垃圾收集算法:

1)複製(Copying)算法,我前面講到的新生代 GC,基本都是基於複製算法,需要預留空間,也需要維護不同複製空間之間對象的關係

2)標記 - 清除(Mark-Sweep)算法,有碎片化問題

3)標記 - 整理(Mark-Compact)

目前還在發展中的前沿 GC 都是複合算法,並且並行和併發兼備。

 

垃圾收集過程:

Java 創建對象,分配在 Eden 區域,當其空間佔用達到一定閾值時,觸發 minor GC。仍然被引用的對象(綠色方塊)存活下來,被複制到 JVM 選擇的 Survivor 區域,而沒有被引用的對象(黃色方塊)則被回收。注意,我給存活對象標記了“數字 1”,這是爲了表明對象的存活時間。第二, 直到再次達到 Minor GC 觸發條件,另外一個 Survivor 區域則會成爲 to 區域,Eden 區域的存活對象和 From 區域對象,都會被複制到 to 區域,並且存活的年齡計數會被加 1。

第三, 類似第二步的過程會發生很多次,直到有對象年齡計數達到閾值,這時候就會發生所謂的晉升(Promotion)過程,如下圖所示,超過閾值的對象會被晉升到老年代。這個閾值是可以通過參數指定。第四後面就是老年代 GC,具體取決於選擇的 GC 選項,對應不同的算法。

老年代 GC 叫作 Major GC,將對整個堆進行的清理叫作 Full GC,不同的老年代 GC 算法其實表現差異很大

 

發展ZGC支持 T bytes 級別的堆大小

選擇:堆大小,比較大,比如16g以上,建議優先g1

開啓GC日誌打印的參數:jdk 9 用 -Xlog:gc*
以前用 -XX:+PringGCStamps -XX:+PringGCDetails

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章