引言
在針對大型伺服器或者是因為gc時間過長而影響使用者效能的時候,G1垃圾收集器是一個非常不錯的選擇,也是我個人認為執行效率最高、對於使用者體驗有著最大的提高的垃圾收集器,當然前提是JVM伺服器記憶體夠大,建議16G或者更大,否則還是推薦使用CMS+ParNew(Old)組合垃圾回收器比較合適。
什麼是G1收集器,有什麼特點G1垃圾收集器全稱是Garbage-First,意義為進行最有價值的垃圾回收(漢語言的優美此刻完美體現)。G1是面向伺服器級的垃圾收集器,主要針對多CPU以及大容量記憶體的機器,具有高吞吐量以及低GC停頓時間。
G1垃圾收集器的堆劃分和其他垃圾收集器不大一樣,G1將java 堆劃分為若干個大小相等的堆記憶體區域,後面稱為region。JVM堆中最多可以存在2048個region,每個region的大小就是堆的記憶體空間除以region個數,當然可以透過配置 -XX:G1HeapRegionSize 引數對region大小進行手動指定,不過因為G1內部有非常多的堆空間最佳化機制,所以推薦使用預設配置,不建議修改。
G1堆記憶體空間示例圖
G1收集器堆空間分割槽情況G1除了有其他垃圾收集器包含的eden、survivor、old外,還有一個特殊的humongous區,專門用於儲存大物件,以下是每個分割槽功能以及特點:
Eden、Survivor:新生代空間,G1中新生代預設初始空間佔比為5%,可以透過配置修改此初始值,不過因為G1內部會在新生代空間不足時,根據內部演算法自動增加新生代記憶體空間,所以不建議修改初始值。JVM在執行過程中,會不斷給新生代空間分配記憶體,最高不超過60%,可以透過 -XX:G1MaxNewSizePercent 引數進行調整。新生代中eden和survior的記憶體分配為8:1:1Humongous:G1大物件分配區,在G1中,大物件的判定規則為超過單個region區域記憶體的50%即為大物件,大物件不需要心如新生代,直接進入humongous區,避免了大物件經歷多次gc,影響jvm整體gc效能,也避免了這種短期生存的大物件擠壓老年代記憶體空間,避免full gc的提前發生。如果單個物件大小超過一個region區域記憶體限制,G1則會給此物件分配多個連續的region空間進行儲存。full gc執行時,也會對humongous區域的物件進行gc回收Old:除了其分佈在多個region空間的特點之外,和其他收集器老年代功能以及用法一致G1垃圾收集過程G1垃圾收集整體過程和CMS類似核心思想也是降低業務執行緒停頓時間,讓業務執行緒和gc執行緒並行工作,提高使用者體驗,不過G1的具體實現上更為優秀(當然大記憶體和CPU資源是必不可少)
初始標記:此階段和CMS初始標記一致,會標記GC Root根直接關聯的物件,此時暫停除GC執行緒外的所有併發標記:此階段和CMS併發標記一致,會併發標記初始標記物件的關聯物件,業務執行緒同時執行,並記錄此時業務執行緒導致的物件引用更新最終標記:此階段和CMS併發標記一致,會修正併發標記階段業務執行緒導致的物件引用更新,此時暫停除GC執行緒以外的執行緒篩選回收:G1的回收演算法使用的是複製演算法,篩選回收的意思是G1會根據 其引數設定對region區域進行選擇性回收,G1內部會分析每個region的回收價值以及回收所需時長,如果單個region的可回收物件大小不足15%(可配置),G1則不會回收此region區域。同時G1會根據region區域需要的回收時長以及JVM設定的GC停頓時間來合理地進行記憶體回收。例如使用者設定的GC停頓時長為100ms,G1會根據後臺維護的優先列表來計算在100ms內能回收的最大region數,回收時間過程的不會進行回收,如果region合計回收時間遠小於100ms,G1也不會進行回收,而是會開闢新的region空間存放物件G1收集器執行示意圖
G1優勢高效能且與支援並行:在多核CPU前提下,充分使用CPU資源,做到併發且並行地進行垃圾收集,極大地減少了 stop the world的時長支援分代收集:G1收集器可以直接對整個JVM 堆進行管理,不像CMS、ParNew等收集器只能對老年代或者新生代進行垃圾清理空間整合:G1收集器採用的是複製收集演算法,效率高於CMS的標記回收演算法停頓時長可設定:G1根據自帶的停頓預測演算法,讓使用者執行緒的停頓時間儘可能借用JVM設定的停頓時間,極大的提升了使用者體驗G1垃圾收集方式YoungGC: 對G1 Eden區記憶體回收的回收方式,不過G1並不是在Eden區一滿就會觸發Young GC,而是會計算當前Eden區如果執行young gc需要執行的時間是否接近 預測停頓時長(透過引數 -XX:MaxGCPauseMills 進行設定),如果接近則會執行young gc,如果遠小於預測停頓時長,則會繼續分配region給eden空間給新物件存放MixedGC:此回收方式會對新生代以及部分老年代以及大物件區進行回收,老年區的回收空間大小是根據G1的內部演算法,結合jvm設定的預測停頓時間,將老年區價值高的垃圾物件優先進行回收,使用的是複製演算法,會將標記的有用物件複製到其他region中,再對需要清除的region進行全量清除,當無剩餘region空間作為複製演算法的目標空間時,就會觸發full gcFullGC: 此回收方式非常簡單粗暴,即使用單執行緒對記憶體空間進行標記清理以及壓縮處理G1收集器引數設定-XX:+UseG1GC:G1開啟引數-XX:ParallelGCThreads:併發標記GC執行緒數-XX:G1HeapRegionSize:指定region分割槽大小,必須是2的整數次冪,最大32m,預設演算法會將jvm堆空間劃分為2048個region-XX:MaxGCPauseMillis:預測GC最大暫停時長,此引數對於G1收集器非常關鍵,預設200毫秒,需要根據具體業務進行設定-XX:G1NewSizePercent:新生代初始記憶體佔比(預設5%,不建議修改)-XX:G1MaxNewSizePercent:新生代最大空間佔比(預設60%,根據實際業務調整)-XX:TargetSurvivorRatio:survivor觸發轉移物件至老年代的閾值(預設50%),當survivor分割槽記憶體空間超過此閾值,會將年齡相比最大的物件移入老年區,直至survivor空間所用記憶體低於閾值-XX:MaxTenuringThreshold:新生代區最大年齡閾值,物件年齡達到此閾值後物件移入老年代-XX:InitiatingHeapOccupancyPercent:老年代空間佔整體堆空間比例超過此閾值時,會觸發mixgc,預設為45%-XX:G1HeapWastePercent:mixgc釋放記憶體空間閾值,當jvm執行mixed gc後,會不斷地有未空閒的region塊被釋放,當釋放的region總記憶體量佔堆空間比例達到此閾值後,停止mixed gc,預設5%-XX:G1MixedGCLiveThresholdPercent:當進行gc時,會計算當前region不可回收物件佔region空間比例,如果該比例高於此閾值,則不會回收,預設85%-XX:G1MixedGCCountTarget:因為G1為了提高使用者體驗,回收過程中的篩選回收會分多次進行,此引數用於這是篩選回收拆分執行次數,預設8次G1收集器使用建議其實所有的垃圾回收器的最佳化都是大同小異,都是需要防止minor gc的頻繁觸發以及防止新生代的短期存活物件進入老年代,而G1收集器最佳化的最重要的點就是 -XX:MaxGCPauseMillis 引數,透過此引數可以設定新生代垃圾回收頻率,同時可以基於對業務的評估,設定此引數,防止survivor區物件超過50%而短期存活物件被迫進入老年代的問題