Java 8 默認(rèn)GC是Parallel GC。設(shè)計初衷避免Full GC
一、Garbage First(G1)
適用服務(wù)器端、大內(nèi)存、多CPU情景。
高效率回收(high thoughput)同時,提供軟實時中斷(所以不是最快,Parallel gc最快)。用戶可指定時間上限,超過打斷回收,恢復(fù)程序執(zhí)行。?
二、收集算法:標(biāo)記-清理 ,拷貝-復(fù)制
http://www.itdecent.cn/p/e37789a2916c另一版本
2.1適用G1案例:
需要大內(nèi)存(堆6GB以上)、?小GC延遲(暫停時間0.5秒以內(nèi))
1、從CMS或者ParallelOld收集器切換到G1場景:
????活動對象占50%以上Java堆空間
????對象分配率或者提升率波動明顯。
? ? 沒有長時間垃圾收集暫停
2、G1特性:像CMS一樣, 能與應(yīng)用程序線程并行;整理空閑空間更快、預(yù)測gc停頓時間;不犧牲大量吞吐性能、不需更大Java Heap
3、G1目標(biāo)是取代CMS,CMS相比,更出色:
1)G1有整理內(nèi)存過程,不產(chǎn)生很多碎片。2)STW可控,添加預(yù)測機(jī)制,可指定https://mp.weixin.qq.com/s/4ufdCXCwO56WAJnzng_-ow
2.2 region:
heap分成若干大小相等region,每個占有一塊連續(xù)虛擬內(nèi)存,都關(guān)聯(lián)Remembered set (RS)。
1、RS數(shù)據(jù)結(jié)構(gòu):hash table,數(shù)據(jù)是card table (heap中每512byte映射在card table 1byte)。RS里面存在region中l(wèi)ive objects指針。
2、region數(shù)據(jù)變化:首先反映到card table中的一個或多個card上,RS通過掃描內(nèi)部的card table得知region中內(nèi)存使用情況和存活對象。

3、大對象H-objs(大于等于region一半)
? ? 1)直接分配到old gen,防止了反復(fù)拷貝移動。
? ? 2)在global concurrent marking階段的cleanup 和 full GC階段回收。
? ? 3)分配前檢查是否超過 initiating heap occupancy percent和the marking threshold, 如超過啟動global concurrent marking,提早回收,防止evacuation failures(疏散失敗)和full GC。
? ? 4)減少連續(xù)H-objs分配對GC影響,把大對象變?yōu)槠胀ǖ膶ο螅ㄗh增大Region size
4、Region大小可設(shè)定:-XX:G1HeapRegionSize,從1M到32M,且是2的指數(shù)。不設(shè)定,根據(jù)Heap大小自動決定。
2.3 關(guān)于內(nèi)存分配:
G1主要關(guān)注于多CPU多線程,內(nèi)存分配用 thread-local allocation buffers (TLABs)。線程都有自己buffers來分配對象,buffers不夠,重新申請一塊內(nèi)存放自己thread-local里。對象內(nèi)存分配被最小化到私有buffers里,緩解并發(fā)分配內(nèi)存壓力。
region滿,分配內(nèi)存線程會選擇新region??誶egion在一個linked list里,快速找新
大對象(大小超過region的3/4)分配TLABs外。分配到特殊區(qū)域(只包含大對象)
2.4執(zhí)行過程:?
初始:STW(Stop the World ),所有mutator threads被停止,標(biāo)記從GC Root開始直接可達(dá)對象,重啟
并發(fā):標(biāo)記與應(yīng)用程序線程并行,耗時長。
最終:標(biāo)記上一階段變化對象。需停頓,也要STW,并行很快完成。
篩選:對每區(qū)回收成本和價值排序,根據(jù)指定停頓時間,選擇性收集,統(tǒng)計每區(qū)對象數(shù)。
三、G1與CMS不同:
1. 分代收集
CMS:只回收老年代(配合年輕代收集器);堆分PermGen,YoungGen(分了兩個survivo),OldGen
G1中:回收老、年輕代,Fully young gc(先回收年輕代垃圾)和Mixed gc(年輕代和老年代,部分回收);?平均分,每個區(qū)也保留了新老代,區(qū)為單位收集

2. 如何處理跨代引用
老引用年輕代影響young gc,需跨代處理。
避免收年輕代時掃描老年代,記錄老對年輕代引用,young gc時只要掃描這個記錄。
CMS(基本用法):JVM將內(nèi)存分成固定大小card,專門數(shù)據(jù)結(jié)構(gòu)Card Table維護(hù)每個Card狀態(tài),一個字節(jié)對應(yīng)一個Card(像內(nèi)存page概念,page是硬件上,Card Table是軟件上)。Card對象引用,對應(yīng)Card Table上狀態(tài)置為dirty,young gc掃描狀態(tài)dirty的Card。
G1:Card Table基礎(chǔ)上引入remembered set(RSet)。每個region維護(hù)一個RSet,記錄著引用Card(其他region)。A對象在regionA,B在regionB,且B.f = A,regionA的RSet中記錄B的Card地址??蓪egion單獨(dú)回收,RSet維護(hù)老到輕、老引用,只掃描region的RSet的Card。
年輕(對象引用變化大)到老年代引用不需單獨(dú)處理,性能提升很大,如都記成本高。只需在老年代維護(hù)Card Table。
3. 處理并發(fā)過程對象變化(未完成)
程序跟gc線程運(yùn)行,新,舊的對象,引用關(guān)系變化。(每行表示一個內(nèi)存狀態(tài),每列表示一個Card,4個):
? ? a)并發(fā)標(biāo)記a:中狀態(tài),標(biāo)記a b c e四個對象,0 1兩個Card已經(jīng)標(biāo)好
? ? b)并發(fā)標(biāo)記同時引用變:g不指d,b不再指c,指向d,這時處理Card 2,標(biāo)記到g,標(biāo)記結(jié)束,導(dǎo)致d對象丟失

(1)CMS初始標(biāo)記:標(biāo)記所有從root直接可達(dá)對象
? ???并發(fā)標(biāo)記:1)從這些對象進(jìn)一步搜索其他可達(dá)對象,構(gòu)成存活對象圖。
?? ?2)Card Table記錄引用變化。但young gc時如dirty card沒包含到年輕代引用,card會重新標(biāo)記為clean,可能將并發(fā)標(biāo)記產(chǎn)生dirty card錯誤清除。
? ? 3)因此CMS引入mod union table,一個bit對應(yīng)一個Card,young gc在將Card Table設(shè)置為clean的時候會將對應(yīng)的mod union table置為dirty。最終標(biāo)記的時候會將Card Table或者mod union table是dirty的Card也作為root去掃描,從而解決并發(fā)標(biāo)記過程產(chǎn)生的引用變化。CMS還需要處理并發(fā)過程從年輕代晉升到老年代的對象,處理方式是將這部分對象也作為root去掃描。
(2)G1用snapshot at the beginning(SATB)算法
GC開始時活對象快照。通過Root Tracing得到,根據(jù)三色標(biāo)記算法,維持并發(fā)GC正確性
? ? ? 初始標(biāo)記時得到一個從root直接可達(dá)的snapshot,snapshot不可達(dá)對象都可gc,1)并發(fā)產(chǎn)生對象都默認(rèn)活,留下一次處理。2)對引用變化,將對應(yīng)Card放SATB隊列里,最終標(biāo)記時處理(如超閾值,并發(fā)標(biāo)記也處理一部分,以隊列中Card作為root進(jìn)行掃描)
4. Write Barrier
寫時插入一條特定操作
CMS:老引用年輕,通過觸發(fā)Write Barrier更新Card Table標(biāo)志位。同步操作,更新引用時順帶執(zhí)行,引入的消耗不大(兩個指令)。
G1復(fù)雜:兩個地方用Write Barrier:
????1.更新RSet的rememberd set Write Barrier:發(fā)生引用更新后,稱Post Write Barrier
????2.?記錄引用變化的Concurrent Marking Write Barrier:發(fā)生引用變化前,稱Pre Write Barrier。為提高性能,兩個Write Barrier先放到隊列中,異步處理
5. Full GC
CMS Full GC原因:Promotion Failure和Concurrent Mode Failure,晉升老年代沒足夠連續(xù)空間,可能內(nèi)存碎片導(dǎo)致;jvm覺得并發(fā)結(jié)束前堆就滿,提前觸發(fā)Full GC。是多線程STW的Mark-Compact過程,需避免或者降低頻率。
G1:Full GC對所有region做Evacuation-Compact(避免FullGC),單線程STW,耗時。原因(類似):1. Evacuation沒有足夠to-space放晉升對象;2. 完成前空間耗盡。
6.算法:
CMS標(biāo)記—清理,G1復(fù)制,保證不產(chǎn)生多余的碎片。
7.G1停頓時間可控:?
目的:減少STW時間,提高吞吐量
提供關(guān)鍵:
避免全域收集,有限時間內(nèi)高效。G1跟蹤各個Region里面的垃圾堆積的價值大?。ɑ厥斋@得空間大小及回收所需時間), 維護(hù)優(yōu)先列表,價值最大Region先(Garbage-First來由)。