G1详解
從CMS垃圾回收器缺點說起
1)過于占用CPU資源,犧牲吞吐量 ?-- 所有回收器的通病
2)并發(fā)清理階段存在浮動垃圾; ? -- 并發(fā)執(zhí)行導致
3)fgc算法是標記清除,會產(chǎn)生磁盤碎片 -- 標記整理算法導致
4)新生代配合ParNewGC使用,存在STW問題。 --- 時間不可控,如果heap很大,可能GC時間很大,影響線上服務
G1起源
一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存(大概6G以上)的機器;
G1從jdk7開始,jdk9被設為默認垃圾收集器;目標就是徹底替換掉CMS
G1內(nèi)存分配策略
將內(nèi)存分成一個一個的region,且不要求各部分是連續(xù)的。
每個Region的大小在JVM啟動時就確定,JVM通常生成2000個左右的heap區(qū), 根據(jù)堆內(nèi)存的總大小,區(qū)的size范圍為1-32Mb,一般4M.
region類型
三種常見: Eden, Survivor, 或 old generation(老年代)區(qū)
巨無霸區(qū):保存比標準region區(qū)大50%及以上的對象,存儲在一組連續(xù)的區(qū)中.轉(zhuǎn)移會影響GC效率,標記階段發(fā)現(xiàn)巨型對象不再存活時,會被直接回收。
未使用區(qū):未被使用的region
特別說明:某個region的類型不是固定的,比如一次ygc過后,原來的Eden的分區(qū)就會變成空閑的可用分區(qū),隨后也可能被用作分配巨型對象
G1中重要的數(shù)據(jù)結(jié)構(gòu)和算法
1 本地線程緩沖區(qū),TLAB
Thread Local Allocation Buffer,默認啟用,分配在Eden空間,屬于單個線程,,每一個線程都有一個TLAB用于分配對象,避免了同步機制使對象盡快的分配出來。
2 晉升本地分配緩沖區(qū),PLAB
Promotion Local Allocation Buffer,晉升的過程,無論是晉升到S還是OLd區(qū),都是在GC線程的PLAB中進行。每個GC線程都有一個PLAB。
3 待收集集合,CSets
Collection Sets,GC中待回收的region的集合。CSet中可能存放著各個分代的Region。CSet中的存活對象會在gc中被移動(復制)。GC后CSet中的region會成為可用分區(qū)。
策略:由G1MixedGCLiveThresholdPercent參數(shù)控制的,old代分區(qū)中的存活對象比,達到閥值時,這個old分區(qū)會被放入CSet,后面會被執(zhí)行回收整理。
4 卡表,Card Table
Java堆劃分為相等大小的一個個區(qū)域,這個小的區(qū)域(一般size在128-512字節(jié))被當做Card,而Card Table維護著所有的Card。Card Table的結(jié)構(gòu)是一個字節(jié)數(shù)組,Card Table用單字節(jié)的信息映射著一個Card。當Card中存儲了對象時,稱為這個Card被臟化了(dirty card)。 對于一些熱點Card會存放到Hot card cache。同Card Table一樣,Hot card cache也是全局的結(jié)構(gòu)。
5 已記憶集合,RSets
RememberedSets,存儲著其他分區(qū)中的對象對本分區(qū)對象的引用,每個分區(qū)有且只有一個RSet。用于提高GC效率。
YGC時,GC root主要是兩類:棧空間和老年代分區(qū)到新生代分區(qū)的引用關(guān)系。所以記錄老年代分區(qū)對新生代分區(qū)的引用
Mixed GC時,由于僅回收部分老年代分區(qū),老年代分區(qū)之間的引用關(guān)系也將被使用。所以記錄老年代分區(qū)之間的引用
因此,我們僅需要記錄兩種引用關(guān)系:老年代分區(qū)引用新生代分區(qū),老年代分區(qū)之間的引用。
因為每次GC都會掃描所有young區(qū)對象,所以RSet只有在掃描old引用young,old引用old時會被使用。
詳細可參考: https://blog.csdn.net/a860MHz/article/details/97276211
6 Snapshot-At-The-Beginning(SATB)
SATB是在G1 GC在并發(fā)標記階段使用的增量式的標記算法。并發(fā)標記是并發(fā)多線程的,但并發(fā)線程在同一時刻只掃描一個分區(qū)。
在解釋SATB前先要了解三色標記法。三色標記法是將對象的存活狀態(tài)用三種顏色標記,從黑色到灰色逐層標記:
黑:該對象被標記了,并且其引用的對象也都被標記完成。
灰:對象被標記了,但其引用的對象還沒有被標記完。
白:對象還沒有被標記,標記階段結(jié)束后,會被回收。
問題場景:
有A->B->C,A是GCRoots關(guān)聯(lián)的對象,那么首先會把GC Roots 標記,也就是A標記成灰色(證明現(xiàn)在正在搜索A相關(guān)的),然后搜索A的引用,也就是B,那么搜索了B,把B變成了灰色,那么A就搜索完成了。A 就變成了黑色,證明 A 已經(jīng) ok 了。
此時準備要搜索 B 了。
剛好,此時,用戶線程要執(zhí)行了,用戶線程把原來 A -> B -> C 的引用改成了 A -> C,同時 B 不再引用C。
最后,C 怎么辦,C還是白色的呢,白色的是不會搜索,當做垃圾處理的。
解決辦法
此時的解決辦法就是有一個叫做寫入屏障的東西。就是說,如果A已經(jīng)被標記了(已經(jīng)是黑色的了),那么用戶線程改動 A->C的時候,會把 C 變成灰色,這樣,以后就可以搜索 C了。
幾個問題:
G1的內(nèi)存占用
如果從 ParallelOldGC或者CMS收集器遷移到G1, 會看到JVM進程占用更多的內(nèi)存,云因就是上面的RSets、CSets、cardTable等。
但是這些加快了gc的速度,減少了stw的時間。
CSet是怎么維護的?怎么知道哪些是要回收的?
由G1MixedGCLiveThresholdPercent參數(shù)控制的,old代分區(qū)中的存活對象比,達到閥值時,說明該region可以被回收的對象比較多,這個old分區(qū)會被放入CSet,等待被GC。
cardTable和region是什么關(guān)系?對region的細分嗎?有什么用?
可以認為region切分為一個一個固定大小card。而CardTable是一個全局的存儲結(jié)構(gòu),其通過一個byte數(shù)組結(jié)構(gòu)存儲了對于每個Card的Entry,其不需要太大的存儲空間。而RSet中的HashTable也就是一些其他Region(引用了RSet所在的Region)的card集合。
參考:https://blog.csdn.net/lijingyao8206/article/details/80513383
cardTable和RSets
RSets:哈希表來存儲,key是region index,value是card數(shù)組
cardTable:記錄多個cardPage信息,單個CardPage大小為512字節(jié),卡表(Card Table)被實現(xiàn)為一個簡單的字節(jié)數(shù)組,即卡表的每個標記項為1個字節(jié)。當對一個對象引用進行寫操作時(對象引用改變),寫屏障邏輯將會標記對象所在的卡頁為dirty。如:
CARD_TABLE [this address >> 9] = 0;
G1垃圾回收方式
整體回收算法
收集整體是使用“標記-整理”,Region之間基于“復制”算法,GC后會將存活對象復制到可用分區(qū)(未分配的分區(qū)),所以不會產(chǎn)生空間碎片。
G1的GC類型
1)Ygc:僅處理年輕代region
2)MixedGc:包含所有年輕代以及部分老年代Region。
3)FullGc:全堆掃描,每個Region
GC原則
G1Gc會在無法分配對象或者巨型對象無法獲得連續(xù)分區(qū)來分配空間時,優(yōu)先嘗試擴展堆空間來獲得更多的可用分區(qū)。
原則上G1會計算執(zhí)行GC的時間,并且極力減少花在GC上的時間(包括ygc,mixgc),如果可能,會通過不斷擴展堆空間來滿足對象分配、轉(zhuǎn)移的需要。
youngGC
觸發(fā):分配一般對象(非巨型對象)時,當所有eden的region使用達到最大閥值并且無法申請足夠內(nèi)存時。
younggc會回收所有Eden以及Survivor區(qū),并且將存活對象復制到Old區(qū)以及另一部分的Survivor區(qū)。到Old區(qū)的標準就是在PLAB中得到的計算結(jié)果。因為YoungGC會進行根掃描,所以會stop the world。
YoungGC的回收過程如下:
根掃描,跟CMS類似,Stop the world,掃描GC Roots對象。
處理Dirty card(即保存了對象的小區(qū)域), 更新RSet(分區(qū)間對象的引用關(guān)系)。
掃描RSet,掃描old區(qū)對象對于本young區(qū)的引用。
拷貝掃描出的存活的對象到survivor2或old區(qū)
處理引用隊列,軟引用,弱引用,虛引用
MixGC
觸發(fā):一次YoungGc之后,老年代占據(jù)堆內(nèi)存的百占比超過InitiatingHeapOccupancyPercent(默認45%)時,超過這個值就會觸發(fā)mixedGC。
混合回收都是基于復制算法進行的,把要回收的Region區(qū)存活的對象放入其他Region,然后這個Region全部清理掉,這樣就會不斷空出來新的Region;
有一個參數(shù)-XX:G1HeapWastePercent,默認值5%,即空出來的區(qū)域大于整個堆的5%,就會立即停止混合回收了。如正常默認回收次數(shù)是8次,但是可能到了4次,空閑Region大于整個堆的5%,就不會再進行后續(xù)回收了。
youngGC后,直接復用YoungGC的全局的根掃描結(jié)果(可提高效率),只回收部分老年代的Region
MixGc過程:
1)標記GCroots,一般直接復用YoungGC中的結(jié)果
2)根分區(qū)掃描(RootRegionScan)。這個階段GC的線程可以和應用線程并發(fā)運行。其主要掃描初始標記以及之前YoungGC對象轉(zhuǎn)移到的Survivor分區(qū),并標記Survivor區(qū)中引用的對象。所以此階段的Survivor分區(qū)也叫根分區(qū)(RootRegion)
3)并發(fā)標記(ConcurrentMark)。會并發(fā)標記所有非完全空閑的分區(qū)的存活對象,也即使用了SATB算法,標記各個分區(qū)。
4)最終標記(Remark)。主要處理SATB緩沖區(qū),以及并發(fā)標記階段未標記到的漏網(wǎng)之魚(存活對象),會STW,可以參考上文的SATB處理。
5)清除階段(Clean UP)。整理堆分區(qū),調(diào)整相應的RSet(比如如果其中記錄的Card中的對象都被回收,則這個卡片的也會從RSet中移除),如果識別到了完全空的分區(qū),則會清理這個分區(qū)的RSet。這個過程會STW。
6)對存活對象進行轉(zhuǎn)移(復制算法),轉(zhuǎn)移到其他可用分區(qū),所以當前的分區(qū)就變成了新的可用分區(qū)。復制轉(zhuǎn)移主要是為了解決分區(qū)內(nèi)的碎片問題。
FullGc
G1在對象復制/轉(zhuǎn)移失敗或者沒法分配足夠內(nèi)存(比如巨型對象沒有足夠的連續(xù)分區(qū)分配)時,會觸發(fā)FullGC。
開始版本FullGC使用的是stop the world的單線程的Serial Old模式。
JDK10以后,Full GC已經(jīng)是并行運行,在很多場景下,其表現(xiàn)還略優(yōu)于 Parallel GC 的并行 Full GC 實現(xiàn)。
但是仍然要避免fgc。
G1適用場景
G1的首要目標是為需要大量內(nèi)存的系統(tǒng)提供一個保證GC低延遲的解決方案. 也就是說堆內(nèi)存最低在6GB及以上,穩(wěn)定和可預測的暫停時間小于0.5秒.
如果應用程序具有如下的一個或多個特征,那么將垃圾收集器從CMS或ParallelOldGC切換到G1將會大大提升性能.
1)Full GC 次數(shù)太頻繁或者消耗時間太長.
2)受夠了太長的垃圾回收或內(nèi)存整理時間(0.5-1s)
最佳實踐指導
1 不要設置年輕代的大小
通過 -Xmn 顯式地指定了年輕代的大小, 會干擾到 G1收集器的默認行為.
1)G1在垃圾收集時將不再關(guān)心暫停時間指標. 所以從本質(zhì)上說,設置年輕代的大小將禁用暫停時間目標.
2)G1在必要時也不能夠增加或者縮小年輕代的空間. 因為大小是固定的,所以對更改大小無能為力.
G1收集器在運行的時候會調(diào)整新生代和老年代的大小。通過改變代的大小來調(diào)整對象晉升的速度以及晉升年齡,從而達到我們?yōu)槭占髟O置的暫停時間目標。設置了新生代大小相當于放棄了G1為我們做的自動調(diào)優(yōu)。我們需要做的只是設置整個堆內(nèi)存的大小,剩下的交給G1自己去分配各個代的大小。所以一般不要設置年輕代大小。
但在某些情況下,通過設置這些值會比G1算法更準確地反映新/舊堆的正確分布.
2 設置 XX:MaxGCPauseMillis=<N>
其值不應該使用平均響應時間,應該考慮使用目標時間的90%或者更小作為響應時間指標. 即90%的用戶(客戶端/?)請求響應時間不會超過預設的目標值;
3 轉(zhuǎn)移失敗
survivors 或 promoted objects 進行GC時如果JVM的heap區(qū)不足就會發(fā)生提升失敗(promotion failure). 堆內(nèi)存不能繼續(xù)
擴充,因為已經(jīng)達到最大值了. 當使用 -XX:+PrintGCDetails 時將會在GC日志中顯示 to-space overflow (to-空間溢出)。該操作很昂貴,原因如下:
1)GC仍繼續(xù)所以空間必須被釋放.?
2)拷貝失敗的對象必須被放到正確的位置(tenured in place).?
3)CSet指向區(qū)域中的任何 RSets 更新都必須重新生成(regenerated).?
避免轉(zhuǎn)移失敗的方法:
1)增加保留內(nèi)存大小, 其默認值是 10;G1保留內(nèi)存大小,非必須不會使用保留內(nèi)存;即增大-XX:G1ReservePercent=n
2)更早啟動標記周期(marking cycle).即InitiatingHeapOccupancyPercent設置的小一點??
3)增加標記線程(marking threads)的數(shù)量. 合理設置-XX:ConcGCThreads=n
4 新生代優(yōu)化-避免短生命對象進入老年代
預估每次Minor GC后存活下來對象的大小,合理的設置Survivor區(qū),同時考慮高峰期間時,動態(tài)年齡判斷條件的影響,不要讓這種短生命周期對象僥幸逃脫進入老年代
5 老年代
系統(tǒng)的停頓時間時關(guān)鍵!是核心,要預測停頓時間,并不是越小越好,過小則回收效果不大
即-XX:MaxGCPauseMills參數(shù)優(yōu)化
這個參數(shù)是核心點!如果參數(shù)設置的值很大,導致系統(tǒng)運行很久,新生代可能都占用了堆內(nèi)存的60%了,此時才觸發(fā)新生代GC,那么存活下來的對象可能就會很多,此時就會導致Survivor區(qū)域放不下那么多的對象(或是動態(tài)年齡判定規(guī)則),就會進入老年代中。
如果參數(shù)設置過小,即使GC停頓時間很短,但GC頻率太大,比如說30秒觸發(fā)一次新生代gc,每次就停頓30毫秒,這樣也是很影響系統(tǒng)性能的。或者GC頻率過高,也可能會導致對象很容易就進入了老年代,這樣也是有問題
來源:
https://www.cnblogs.com/yuanzipeng/p/13374690.html
https://backstage.forgerock.com/knowledge/kb/article/a75965340
G1相關(guān)的參數(shù)
-XX:MaxGCPauseMillis=200 - 設置最大GC停頓時間指標,JVM會盡力實現(xiàn),但不保證. 默認值為200毫秒.
-XX:InitiatingHeapOccupancyPercent=45 - 如果老年代占據(jù)了堆內(nèi)存的45%的時候,此時會觸發(fā)一次mixGc。值為0則表示“一直執(zhí)行GC循環(huán))'. 默認值為45。
-XX:G1MixedGCLiveThresholdPercent:默認值是85%,確定要回收的Region的時候,必須是存活對象低于85%的Region才可以回收。
-XX:G1ReservePercent=n 設置堆內(nèi)存保留為假天花板的總量,以降低提升失敗的可能性. 默認值是 10.
-XX:ConcGCThreads=n 并發(fā)垃圾收集器使用的線程數(shù)量. 默認值隨JVM運行的平臺不同而不同.
-XX:+UseG1GC - 讓 JVM使用G1垃圾收集器, jdk9被設為默認垃圾收集器;所以如果你的版本比較新則不再需要使用該參數(shù)
-XX:MetaspaceSize=256M 元空間,默認20M,確實有點小。
-XX:MaxMetaspaceSize=512M 最大元空間
下面參數(shù)不建議修改
-XX:G1NewSizePercent=5?? ?設置年輕代占整個堆的最小百分比,默認值是堆的5%。需要開啟-XX:UnlockExperimentalVMOptions
-XX:G1MaxNewSizePercent=60?? ?設置年輕代占整個堆的最大百分比,默認值是堆的60%。
-XX:NewRatio=n 新生代與老生代(new/old generation)的大小比例(Ratio). 默認值為 2.
-XX:SurvivorRatio=n eden/survivor 空間大小的比例(Ratio). 默認值為 8.
-XX:MaxTenuringThreshold=n 年輕代提升到年老代的最大臨界值. 默認值為 15.
-XX:G1HeapRegionSize=n region大小 ?默認值將根據(jù) heap size 算出最優(yōu)解;1M-32M
-XX:G1MixedGCCountTarget mixed回收執(zhí)行次數(shù),默認回收次數(shù)8。
-XX:G1HeapWastePercent,默認值是5%,就是說空出來的區(qū)域大于整個堆的5%,即使未達到回收次數(shù),也會立即停止混合回收了。
如:默認回收次數(shù)是8次,但是可能到了4次,發(fā)現(xiàn)空閑Region大于整個堆的5%,就不會再進行后續(xù)回收了。
可參考官網(wǎng)說明:https://docs.oracle.com/en/java/javase/13/docs/specs/man/java.html
查看系統(tǒng)默認參數(shù)配置,如G1ReservePercent: ?java -XX:+PrintFlagsFinal ?| grep G1ReservePercent
JVM初始分配的堆內(nèi)存由-Xms指定,默認是物理內(nèi)存的1/64;
JVM最大分配的堆內(nèi)存由-Xmx指定,默認是物理內(nèi)存的1/4。
默認空余堆內(nèi)存小于40%時,JVM就會增大堆直到-Xmx的最大限制;空余堆內(nèi)存大于70%時,JVM會減少堆直到-Xms的最小限制。
G1的gc日志
ps -ef | grep java
其中-Xlog:gc*:file=/data/logs/gc_log/api-gc.log 說明了gc日志路徑
凌晨4點啟動后剛開始的日志:
?more /data/logs/gc_log/coding-api-gc.log
[0.004s][info][gc,heap] Heap region size: 4M //每個region大小
[0.033s][info][gc ? ? ] Using G1?
[0.033s][info][gc,heap,coops] Heap address: 0x0000000500000000, size: 12288 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.033s][info][gc,cds ? ? ? ] Mark closed archive regions in map: [0x00000007ffc00000, 0x00000007ffc79ff8]
[0.033s][info][gc,cds ? ? ? ] Mark open archive regions in map: [0x00000007ffb00000, 0x00000007ffb47ff8]
[0.046s][info][gc ? ? ? ? ? ] Periodic GC disabled
*************下面開始第一次gc
[1.844s][info][gc,start ? ? ] GC(0) Pause Young (Concurrent Start) (Metadata GC Threshold) //在新生代進行垃圾回收
[1.844s][info][gc,task ? ? ?] GC(0) Using 8 workers of 8 for evacuation ?//使用8條垃圾回收線程
[1.923s][info][gc,phases ? ?] GC(0) ? Pre Evacuate Collection Set: 0.7ms
[1.923s][info][gc,phases ? ?] GC(0) ? Evacuate Collection Set: 76.6ms
[1.923s][info][gc,phases ? ?] GC(0) ? Post Evacuate Collection Set: 1.2ms
[1.923s][info][gc,phases ? ?] GC(0) ? Other: 1.1ms
[1.923s][info][gc,heap ? ? ?] GC(0) Eden regions: 115->0(139)
[1.923s][info][gc,heap ? ? ?] GC(0) Survivor regions: 0->14(20)
[1.923s][info][gc,heap ? ? ?] GC(0) Old regions: 0->0
[1.923s][info][gc,heap ? ? ?] GC(0) Archive regions: 2->2
[1.923s][info][gc,heap ? ? ?] GC(0) Humongous regions: 0->0
[1.923s][info][gc,metaspace ] GC(0) Metaspace: 20586K->20586K(1067008K)
[1.923s][info][gc ? ? ? ? ? ] GC(0) Pause Young (Concurrent Start) (Metadata GC Threshold) 463M->56M(12288M) 79.600ms
[1.923s][info][gc,cpu ? ? ? ] GC(0) User=0.10s Sys=0.03s Real=0.08s
[1.923s][info][gc ? ? ? ? ? ] GC(1) Concurrent Cycle ?//并發(fā)標記周期 ? ??
[1.923s][info][gc,marking ? ] GC(1) Concurrent Clear Claimed Marks ? //初始標記
[1.923s][info][gc,marking ? ] GC(1) Concurrent Clear Claimed Marks 0.027ms
[1.923s][info][gc,marking ? ] GC(1) Concurrent Scan Root Regions ? //掃描GCroot所在的region
[1.938s][info][gc,marking ? ] GC(1) Concurrent Scan Root Regions 15.193ms
[1.938s][info][gc,marking ? ] GC(1) Concurrent Mark (1.938s) ?//并發(fā)標記
[1.938s][info][gc,marking ? ] GC(1) Concurrent Mark From Roots
[1.938s][info][gc,task ? ? ?] GC(1) Using 2 workers of 2 for marking
[1.942s][info][gc,marking ? ] GC(1) Concurrent Mark From Roots 3.189ms
[1.942s][info][gc,marking ? ] GC(1) Concurrent Preclean ? ? ?//并發(fā)預清理
[1.942s][info][gc,marking ? ] GC(1) Concurrent Preclean 0.123ms
[1.942s][info][gc,marking ? ] GC(1) Concurrent Mark (1.938s, 1.942s) 3.345ms
[1.942s][info][gc,start ? ? ] GC(1) Pause Remark ? //暫停標記
[1.943s][info][gc ? ? ? ? ? ] GC(1) Pause Remark 62M->62M(12288M) 1.449ms
[1.943s][info][gc,cpu ? ? ? ] GC(1) User=0.01s Sys=0.00s Real=0.00s
[1.943s][info][gc,marking ? ] GC(1) Concurrent Rebuild Remembered Sets ?//重新構(gòu)建remembered sets
[1.944s][info][gc,marking ? ] GC(1) Concurrent Rebuild Remembered Sets 0.816ms
[1.944s][info][gc,start ? ? ] GC(1) Pause Cleanup
[1.945s][info][gc ? ? ? ? ? ] GC(1) Pause Cleanup 62M->62M(12288M) 0.377ms
[1.945s][info][gc,cpu ? ? ? ] GC(1) User=0.00s Sys=0.00s Real=0.00s
[1.945s][info][gc,marking ? ] GC(1) Concurrent Cleanup for Next Mark
[2.021s][info][gc,marking ? ] GC(1) Concurrent Cleanup for Next Mark 75.935ms
[2.021s][info][gc ? ? ? ? ? ] GC(1) Concurrent Cycle 97.722ms
[3.762s][info][gc,start ? ? ] GC(2) Pause Young (Concurrent Start) (Metadata GC Threshold)
[3.762s][info][gc,task ? ? ?] GC(2) Using 8 workers of 8 for evacuation
[3.813s][info][gc,phases ? ?] GC(2) ? Pre Evacuate Collection Set: 0.7ms
[3.813s][info][gc,phases ? ?] GC(2) ? Evacuate Collection Set: 48.3ms
[3.813s][info][gc,phases ? ?] GC(2) ? Post Evacuate Collection Set: 1.4ms
[3.813s][info][gc,phases ? ?] GC(2) ? Other: 0.6ms
[3.813s][info][gc,heap ? ? ?] GC(2) Eden regions: 121->0(149)
[3.813s][info][gc,heap ? ? ?] GC(2) Survivor regions: 14->4(20)
[3.813s][info][gc,heap ? ? ?] GC(2) Old regions: 0->14
[3.813s][info][gc,heap ? ? ?] GC(2) Archive regions: 2->2
[3.813s][info][gc,heap ? ? ?] GC(2) Humongous regions: 0->0
[3.813s][info][gc,metaspace ] GC(2) Metaspace: 35026K->35026K(1081344K)
[3.813s][info][gc ? ? ? ? ? ] GC(2) Pause Young (Concurrent Start) (Metadata GC Threshold) 538M->71M(12288M) 51.174ms
[3.813s][info][gc,cpu ? ? ? ] GC(2) User=0.25s Sys=0.05s Real=0.05s
11小時后下午3點左右的日志:
[38918.626s][info][gc,start ? ? ] GC(101) Pause Young (Normal) (G1 Evacuation Pause)
[38918.626s][info][gc,task ? ? ?] GC(101) Using 8 workers of 8 for evacuation
[38918.639s][info][gc,phases ? ?] GC(101) ? Pre Evacuate Collection Set: 0.6ms
[38918.639s][info][gc,phases ? ?] GC(101) ? Evacuate Collection Set: 10.4ms
[38918.639s][info][gc,phases ? ?] GC(101) ? Post Evacuate Collection Set: 1.8ms
[38918.639s][info][gc,phases ? ?] GC(101) ? Other: 0.6ms
[38918.639s][info][gc,heap ? ? ?] GC(101) Eden regions: 1840->0(1840)
[38918.639s][info][gc,heap ? ? ?] GC(101) Survivor regions: 3->3(231)
[38918.639s][info][gc,heap ? ? ?] GC(101) Old regions: 41->41
[38918.639s][info][gc,heap ? ? ?] GC(101) Archive regions: 2->2
[38918.639s][info][gc,heap ? ? ?] GC(101) Humongous regions: 2->2
[38918.639s][info][gc,metaspace ] GC(101) Metaspace: 156518K->156518K(1193984K)
[38918.639s][info][gc ? ? ? ? ? ] GC(101) Pause Young (Normal) (G1 Evacuation Pause) 7547M->186M(12288M) 13.485ms
[38918.639s][info][gc,cpu ? ? ? ] GC(101) User=0.09s Sys=0.00s Real=0.02s
[39117.315s][info][gc,start ? ? ] GC(102) Pause Young (Normal) (G1 Evacuation Pause)
[39117.315s][info][gc,task ? ? ?] GC(102) Using 8 workers of 8 for evacuation
[39117.328s][info][gc,phases ? ?] GC(102) ? Pre Evacuate Collection Set: 0.6ms
[39117.328s][info][gc,phases ? ?] GC(102) ? Evacuate Collection Set: 10.1ms
[39117.328s][info][gc,phases ? ?] GC(102) ? Post Evacuate Collection Set: 1.9ms
[39117.328s][info][gc,phases ? ?] GC(102) ? Other: 0.6ms
[39117.328s][info][gc,heap ? ? ?] GC(102) Eden regions: 1840->0(1840)
[39117.328s][info][gc,heap ? ? ?] GC(102) Survivor regions: 3->3(231)
[39117.328s][info][gc,heap ? ? ?] GC(102) Old regions: 41->41
[39117.328s][info][gc,heap ? ? ?] GC(102) Archive regions: 2->2
[39117.328s][info][gc,heap ? ? ?] GC(102) Humongous regions: 2->2
[39117.328s][info][gc,metaspace ] GC(102) Metaspace: 156519K->156519K(1193984K)
[39117.328s][info][gc ? ? ? ? ? ] GC(102) Pause Young (Normal) (G1 Evacuation Pause) 7546M->186M(12288M) 13.206ms
[39117.328s][info][gc,cpu ? ? ? ] GC(102) User=0.09s Sys=0.00s Real=0.01s
userTime是指gc花費的所有CPU時間之和,realTime是指gc暫停的實際時間。
下面三個都是什么含義??
[38918.626s][info][gc,start ? ? ] GC(101) Pause Young (Normal) (G1 Evacuation Pause) 新生代--發(fā)生于后期
[3.762s][info][gc,start ? ? ] GC(2) Pause Young (Concurrent Start) (Metadata GC Threshold) ?-元空間擴容- 項目啟動
[1.923s][info][gc ? ? ? ? ? ] GC(1) Concurrent Cycle ?//并發(fā)標記周期 ? ? 項目啟動
GC pause (G1 Evacuation Pause) (mixed)?
是不是沒有發(fā)生過mixedGc,需要一個機器不重啟查看,至今還沒弄明白
元數(shù)據(jù)擴容:
1)新生代并發(fā)回收 ?Pause Young (Concurrent Start) (Metadata GC Threshold)
2)并發(fā)周期標記 ? Concurrent Cycle
3)(Concurrent Start) (Metadata GC Threshold)
4) Concurrent Cycle
5) Pause Young (Concurrent Start) (Metadata GC Threshold)
6) Concurrent Cycle
7) Pause Young (Concurrent Start) (Metadata GC Threshold)
8) Concurrent Cycle
gc次數(shù)統(tǒng)計
jstat -gc 22332
?S0C ? ?S1C ? ?S0U ? ?S1U ? ? ?EC ? ? ? EU ? ? ? ?OC ? ? ? ? OU ? ? ? MC ? ? ? MU ? ? ? CCSC ? ?CCSU ? ? ?YGC ? ? YGCT ? ?FGC ? ?FGCT ? ?CGC ? ?CGCT ? ? GCT
?0.0 ?12288.0 ?0.0 ? 11505.7 7917568.0 4788224.0 4653056.0 ? 196096.5 163632.0 156534.1 19580.0 16987.9 ? ? 98 ? ?1.760 ? 0 ? ? ?0.000 ? 10 ? ? ?0.021 ? ?1.781
jstat -gc結(jié)果中CCSC和CCSU、CGC、CGCT分別是什么?
CCSC:壓縮類空間大小
CCSU:壓縮類空間使用大小
CGC:Concurrent gc,metaspace擴容的時候就發(fā)生了
CGCT:Concurrent gc time
G1的優(yōu)缺點
缺點
region 大小和大對象很難保證一致,這會導致空間的浪費;特別大的對象是可能占用超過一個 region 的。并且,region 太小不合適,會令你在分配大對象時更難找到連續(xù)空間,這是一個長久存在的情況。
因為CSet、Rsets、CardTable等數(shù)據(jù)的存在,會比較耗費內(nèi)存。
優(yōu)點
1、可根據(jù)用戶設置停頓時間,制定回收計劃(但是也可能存在超出用戶的停頓時間). ?--- 最主要的目標
2、局部上來看是基于“復制”算法實現(xiàn)的,無磁盤碎片。
3、對GC停頓可以做更好的預測
總結(jié)
G1最大的特性/優(yōu)點,就是對停頓時間的處理,一方面通過統(tǒng)計數(shù)據(jù)結(jié)構(gòu)(會耗費更多內(nèi)存)、參數(shù)配置實現(xiàn)控制和預測停頓時間,另一方面對于大內(nèi)存的回收采取分批回收的方式,降低單次GC的停頓時間,避免影響主業(yè)務。
G1怎么實現(xiàn)的回收時間可控
1)追蹤每一個Region的回收價值,所謂回收價值就是根據(jù)設定的預期系統(tǒng)停頓時間,來選擇最少回收時間和最多回收對象的Region進行垃圾回收,保證每次回收都是最有效的回收
2)如果需要被Gc的對象很多,保證GC對系統(tǒng)停頓的影響在可控范圍內(nèi),采取分批循環(huán)回收的策略,盡量保證單次服務停頓滿足要求。
核心思想:貪心算法 + 分批回收
G1和CMS適用場景
實際用cms的挺多,也有更多經(jīng)驗;
如果都不熟,先看看g1能否達到你的延遲、吞吐目標;
還有基礎(chǔ)配置,如堆大小,比較大,比如16g以上,建議優(yōu)先g1;30G以上慎用CMS
如果gc是stw時間過長,一般也是通過G1來解決
最新的回收器
Epsilon GC,簡單說就是個不做垃圾收集的 GC,似乎有點奇怪,有的情況下,例如在進行性能測試的時候,可能需要明確判斷 GC 本身產(chǎn)生了多大的開銷,這就是其典型應用場景。
ZGC,Oracle開源出來的一個超級GC實現(xiàn),具備令人驚訝的擴展能力,比如支持Tbytes 級別的堆大小,并且保證絕大部分情況下,延遲都不會超過10ms。雖然目前還處于實驗階段,僅支持 Linux 64 位的平臺,但其已經(jīng)表現(xiàn)出的能力和潛力都非常令人期待。可參考:https://mp.weixin.qq.com/s/ag5u2EPObx7bZr7hkcrOTg
?
gc日志參考url
https://blog.csdn.net/weixin_43931625/article/details/105031002
https://www.cnblogs.com/javaadu/p/11220234.html
https://www.cnblogs.com/javaadu/p/11742585.html ?
優(yōu)化參考:
https://blog.csdn.net/weixin_45410925/article/details/102386767
-XX:+UseStringDeduplication
https://blog.csdn.net/weishuai528/article/details/96899513
-Xms128M -Xmx2048M
可參考url:
https://blog.csdn.net/lijingyao8206/article/details/80513383 ---好文章
https://www.cnblogs.com/ASPNET2008/p/6496481.html??
https://blog.csdn.net/qq_27529917/article/details/86664677 --參數(shù)
https://blog.csdn.net/qq_43294955/article/details/105565152 --優(yōu)質(zhì), G1垃圾回收器詳解與回收性能優(yōu)化
https://docs.oracle.com/cd/E40972_01/doc.70/e40973/cnf_jvmgc.htm#autoId0
總結(jié)
- 上一篇: ubuntu如何连接显示器
- 下一篇: 正则表达式匹配身份证 电话号码 邮箱 住