摘要:注意到通過并發(fā)更新它們來幫助維護(hù)通常在應(yīng)用運(yùn)行期間。累積狀態(tài)包括的總和和最大數(shù)量,已占用的數(shù)量,最大尺寸信息。階段期間和標(biāo)記期間并發(fā)標(biāo)記多階段的一部分處理引用。之后,期間的清除階段死亡的被回收。
原文出處:Tips for Tuning the Garbage First Garbage Collector
這是由兩部分組成的系列的第二篇關(guān)于G1垃圾回收器的文章,你可以在2013.07.17的InfoQ上找到第一部分:G1: One Garbage Collector To Rule Them All。
在我我們了解如何調(diào)整G1 GC之前,首先我必須了解G1定義的關(guān)鍵概念。在這篇文章里,我會(huì)首先介紹概念,然后討論如何調(diào)整G1(適當(dāng)?shù)臅r(shí)候)。
Remembered Sets
從之前的文章回憶起它:Remembered Sets(RSets)是每一個(gè)region里面幫助G1 GC追蹤外部指向這個(gè)region的引用。因此現(xiàn)在,取代因?yàn)橐弥赶蜻@個(gè)region掃描整個(gè)heap區(qū),G1只需要掃描RSets。
1: Remembered Sets
我們看一下示意圖。上面的示意圖向我們展示三個(gè)region(灰色)。Region 1, Region 2和Region 3和它們關(guān)聯(lián)的RSets(粉紅色),RSets代表一些card的集合。Region 1和Region 3恰好引用Region2里的對象。因此,Region 2的RSets記錄了兩個(gè)引用Region2的對象,Region2就是“owning region”。
這里有兩個(gè)概念幫助理解RSets:
Post-write barriers
Concurrent refinement threads
屏障代碼在寫操作之后(因此名稱是“post-write barrier”),為了記錄幫助追蹤跨region更新。包含更新引用字段的card更新可靠的日志緩沖區(qū)。一旦這些緩沖區(qū)滿了,它們就停止工作。Concurrent refinement threads處理這些緩沖區(qū)日志。
注意到Concurrent refinement threads通過并發(fā)更新它們來幫助維護(hù)RSets(通常在應(yīng)用運(yùn)行期間)。Concurrent refinement threads調(diào)度是分層的。開始只有少量的線程被部署,最終添加取決于更新充滿緩沖區(qū)操作的數(shù)量。concurrent refinement threads的最大數(shù)量可以由-XX:G1ConcRefinementThreads或者-XX:ParallelGCThreads控制。如果concurrent refinement threads的數(shù)量趕不上裝滿緩沖區(qū)的數(shù)量,然后mutator threads處理緩沖區(qū)過程-通常你應(yīng)該努力去避免這中情況。
OK,回到RSets-每一個(gè)Region有一個(gè)RSets。RSets由三種級別的粒度-Sparse, Fine和Coarse。一個(gè)Per-Region-Table (PRT)是RSet存儲(chǔ)顆粒度級別一個(gè)抽象。sparse PRT是一個(gè)包含Card目錄的hash table。G1 GC內(nèi)部維護(hù)這些card。card包含來自region的引用,這個(gè)region的引用是card到“owning region”的關(guān)聯(lián)的地址。fine-grain PRT是一個(gè)開放的hash table,每一個(gè)entry代表一個(gè)指向owning region的引用的region。region里面的card目錄,是一個(gè)bitmap。當(dāng)達(dá)到fine-grain PRT的最大容量,coarse grain bitmap里面的相應(yīng)的coarse-grained bit被設(shè)置,相應(yīng)地entry從 fine grain PRT刪除。coarse bitmap有一個(gè)每個(gè)region對應(yīng)的bit。coarse grain map設(shè)置bit意味著關(guān)聯(lián)的region包含到“owning region”的引用。
Collection Set (CSet)是一個(gè)gc期間即將被回收的region的set。對于 Young gc,CSet只包含Young Region,對于混合回收,CSets包含Young Region和Old Region。
如果CSets包含許多攜帶coarsened RSets的Region(注意,“coarsening of RSets”是根據(jù)RSets貫穿不同級別顆粒度的過渡期定義的),然后你會(huì)看到掃描RSets消耗時(shí)間的增長。GC階段這些掃描時(shí)間就是GC日志里面的“Scan RS (ms)”。如果RSets掃描時(shí)間相當(dāng)于GC階段總時(shí)間很高,或者你的應(yīng)用中它們表現(xiàn)很高,然后通過使用診斷選項(xiàng)-XX:+G1SummarizeRSetStats請觀察你的 Young GC 日志輸出的“Did xyz coarsenings”(你可以通過設(shè)置-XX:G1SummarizeRSetStatsPeriod=period指定周期頻率報(bào)告(GCs的數(shù)量))。
如果你回想起之前的文章,GC階段的“Update RS (ms)”展示了更新RSets花費(fèi)時(shí)間,"Processed Buffers" 展示了GC期間更新緩沖區(qū)過程。如果你的日志中發(fā)現(xiàn)這些問題,然后使用上述的選項(xiàng)去進(jìn)一步深入這些問題。
哪些選項(xiàng)通??梢詭椭_定更新日志緩沖區(qū)和concurrent refinement threads的問題。
-XX:+G1SummarizeRSetStats 設(shè)置成一-XX:G1SummarizeRSetStatsPeriod=1的輸出樣例:
上面的輸出展示了已經(jīng)處理過的card和已完成的buffer的數(shù)量。它展示concurrent refinement threads做了100%的工作,mutator threads 什么也沒有做(這是我們說過的一個(gè)號的跡象!)。然后列出concurrent refinement thread的每一個(gè)線程攝入到工作的時(shí)間。
上面褐色的部分展示了自從HotSpot VM啟動(dòng)以來的累積狀態(tài)。累積狀態(tài)包括RSets的總和和最大RSets數(shù)量,已占用Card的數(shù)量,最大Region尺寸信息。它通常展示自VM啟動(dòng)以來任務(wù)完成的粗化總數(shù)。
此時(shí)此刻,介紹其他選項(xiàng)是合適的-XX:G1RSetUpdatingPauseTimePercent=10。設(shè)置GC evacuation(疏散)階段期間G1 GC更新RSets消耗時(shí)間的百分比(默認(rèn)是目標(biāo)停頓時(shí)間的10%)。你可以增大或減小百分比的值,以便在stop-the-world(STW)GC階段花費(fèi)更多或更少的時(shí)間,讓concurrent refinement thread處理相應(yīng)的緩沖區(qū)。
記住,減少百分比的值,你在推遲concurrent refinement thread的工作;因此,你會(huì)看到并發(fā)任務(wù)增加。
Reference Processing
evacuation階段期間和標(biāo)記期間(并發(fā)標(biāo)記多階段的一部分)G1 GC處理引用。
evacuation階段期間,掃描對象,復(fù)制,被處理后的時(shí)候找到引用對象。GC log里面,引用處理(Ref proc)時(shí)間和叫做“Other”下面的一組連續(xù)工作:
Note:無用的引用被添加進(jìn)pending list,GC log里面展示的時(shí)間是reference enqueing time (Ref Enq)。
Remark階段,發(fā)生在并發(fā)標(biāo)記階段之前。(note:多階段并發(fā)標(biāo)記周期的一部分。請參考上篇文章的更多細(xì)節(jié)。)remark階段處理發(fā)現(xiàn)的引用過程。GC log里,你可以在GC remark部分看到reference processing (GC ref-proc)時(shí)間:
如果你看到引用處理期間時(shí)間很長,通過授權(quán)命令行選項(xiàng) -XX:+ParallelRefProcEnabled打開并行引用處理。
Evacuation Failure
如果你在GC日志發(fā)現(xiàn)"evacuation failure", "to-space exhausted", "to-space overflow", "promotion failure"之類的字眼。這些術(shù)語的概念在G1 GC是相似的,請參考同一個(gè)。當(dāng)沒有更多的空閑region提升到Old代,或者復(fù)制到survivor空間,heap由于已經(jīng)在最大值上而無法擴(kuò)展,evacuation Failure聚會(huì)發(fā)生:
如果對象被成功復(fù)制,G1需要更新對象引用,region必須是tenured。
如果對象復(fù)制失敗,G1會(huì)自己處理它們,在合適時(shí)機(jī)把region設(shè)置為tenured。
因此在G1 log 發(fā)生evacuation failure你應(yīng)該怎么做:
找出調(diào)整的一些影響導(dǎo)致失敗-獲取heap最大和最小的基線和真實(shí)的停頓時(shí)間目標(biāo):移除任何heap大小的設(shè)置例如-Xmn, -XX:NewSize, -XX:MaxNewSize, -XX:SurvivorRatio等等。只使用-Xms, -Xmx,停頓時(shí)間目標(biāo)-XX:MaxGCPauseMillis。
如果問題在基線運(yùn)行依然存在,大對象(看下面的章節(jié))分配沒有問題-矯正問題的方案是如果可以的話增加heap區(qū)大小。
如果增加heap區(qū)大小行不通,如果你注意到為了G1 GC可以回收Old代標(biāo)記階段不會(huì)提早執(zhí)行,然后你刪掉-XX:MaxGCPauseMillis。這個(gè)選項(xiàng)默認(rèn)占用你heap區(qū)的45%。刪除這個(gè)選項(xiàng)可以幫助提早開始標(biāo)記階段。相反的,如果標(biāo)記階段提早開始并沒有回收到很多空間,你應(yīng)該在threshold默認(rèn)值上增加來確保你的應(yīng)用的存活數(shù)據(jù)可以適應(yīng)。
如果并發(fā)標(biāo)記階段準(zhǔn)時(shí)啟動(dòng),但是花了很長時(shí)間去完成;因此造成mixed gc周期延遲,最后導(dǎo)致evacuation失敗,然后old代沒有及時(shí)回收;使用選項(xiàng)-XX:ConcGCThreads增加并發(fā)標(biāo)記線程數(shù)量。
如果“to-space”Survivor區(qū)域有問題, 增加-XX:G1ReservePercent。默認(rèn)是java heap的10%。G1 GC設(shè)置錯(cuò)誤上限預(yù)留內(nèi)存,以防萬一"to-space"需要更多的空間。當(dāng)然G1 GC只使用空間的50%,因此如果我們不想應(yīng)用使用大的Young可以設(shè)置一個(gè)更大的值。
為了幫助解釋evacuation failure的原因,我想介紹一個(gè)用戶的選項(xiàng):-XX:+PrintAdaptiveSizePolicy。這個(gè)選項(xiàng)會(huì)提供很多方法去阻止-XX:+PrintGCDetails選項(xiàng)。
讓我看一個(gè)-XX:+PrintAdaptiveSizePolicy可用時(shí)的片段:
6062.121: [GC pause (G1 Evacuation Pause) (mixed) 6062.121: [G1Ergonomics (CSet Construction) start choosing CSet, _pending_cards: 129059, predicted base time: 52.34 ms, remaining time: 147.66 ms, target pause time: 200.00 ms] 6062.121: [G1Ergonomics (CSet Construction) add young regions to CSet, eden: 912 regions, survivors: 112 regions, predicted young region time: 256.16 ms] 6062.122: [G1Ergonomics (CSet Construction) finish adding old regions to CSet, reason: old CSet region num reached min, old: 149 regions, min: 149 regions]6062.122: [G1Ergonomics (CSet Construction) finish choosing CSet, eden: 912 regions, survivors: 112 regions, old: 149 regions, predicted pause time: 344.87 ms, target pause time: 200.00 ms] 6062.281: [G1Ergonomics (Heap Sizing) attempt heap expansion, reason: region allocation request failed, allocation request: 2097152 bytes] 6062.281: [G1Ergonomics (Heap Sizing) expand the heap, requested expansion amount: 2097152 bytes, attempted expansion amount: 4194304 bytes] 6062.281: [G1Ergonomics (Heap Sizing) did not expand the heap, reason: heap expansion operation failed] 6062.902: [G1Ergonomics (Heap Sizing) attempt heap expansion, reason: recent GC overhead higher than threshold after GC, recent GC overhead: 20.30 %, threshold: 10.00 %, uncommitted: 0 bytes, calculated expansion amount: 0 bytes (20.00 %)] 6062.902: [G1Ergonomics (Concurrent Cycles) do not request concurrent cycle initiation, reason: still doing mixed collections, occupancy: 9596567552 bytes, allocation request: 0 bytes, threshold: 5798205810 bytes (45.00 %), source: end of GC] 6062.902: [G1Ergonomics (Mixed GCs) continue mixed GCs, reason: candidate old regions available, candidate old regions: 1038 regions, reclaimable: 2612574984 bytes (20.28 %), threshold: 10.00 %] (to-space exhausted), 0.7805160 secs]
上面的片段提供了很多信息-首先,讓我們用上面GC log使用的命令行選項(xiàng) server -Xms12g -Xmx12g -XX:+UseG1GC- -XX:NewSize=4g -XX:MaxNewSize=5g展示一些精彩的東西。
加粗部分展示用戶限制region的范圍在4-5G之間,因此限制了G1 GC的適應(yīng)能力。如果G1需要去掉限制設(shè)置更小的值,它做不到;如果G1 GC需要增加空間范圍,超過了給它分配的空間,它做不到!
這是evacuation結(jié)束時(shí)打印的heap明確信息:
[Eden: 3648.0M(3648.0M)->0.0B(3696.0M) Survivors: 448.0M->400.0M Heap: 11.3G(12.0G)->9537.9M(12.0G)]
階段之后,G1不得不維持4096M作為最小范圍(-XX:NewSize=4g),由于基于G1的計(jì)算器,3696M用于Eden區(qū),400M用戶Survivor區(qū)。然而,heap區(qū)標(biāo)記回收的數(shù)據(jù)已經(jīng)達(dá)到9537.9M。因此,G1用完“to-space”。下面兩次 evacuation階段的結(jié)果是evacuation failure:
混合evacuation階段1:
[Eden: 2736.0M(3696.0M)->0.0B(4096.0M) Survivors: 400.0M->0.0B Heap: 12.0G(12.0G)->12.0G(12.0G)]
混合evacuation階段2:
[Eden: 0.0B(4096.0M)->0.0B(4096.0M) Survivors: 0.0B->0.0B Heap: 12.0G(12.0G)->12.0G(12.0G)]
最終觸發(fā)Full GC:
6086.564: [Full GC (Allocation Failure) 11G->3795M(12G), 15.0980440 secs] [Eden: 0.0B(4096.0M)->0.0B(4096.0M) Survivors: 0.0B->0.0B Heap: 12.0G(12.0G)->3795.2M(12.0G)]
Full GC 可以通過減少范圍/young代縮小至默認(rèn)的minimum(Java heap的5%)。你也許會(huì)說old代足夠容納3795M的live data set (LDS)。然而, LDS明確耦合于設(shè)置young代minimum(4G),壓縮7891M以上空間。因此設(shè)置threshold為默認(rèn)的heap的45%(也就是 5529M左右),標(biāo)記階段提早觸發(fā)
,混合回收期間回收很少的空間。heap使用保持增長,其他的標(biāo)記階段已經(jīng)開始,但是標(biāo)記階段完成,踢開混合GC,已使用空間在11.3G(正如看到heap第一行的信息)。這次回收遭遇evacuation failure。因此,這個(gè)問題陷在 “starting marking cycle too early”上面。
Humongous Allocations
最后一個(gè)我想介紹的概念是,也許用戶創(chuàng)建許多 humongous objects (H-objs),G1 GC處理H-objs。
辣么,我們?yōu)槭裁葱枰煌緩饺シ峙銱-objs?
如果對象占用Region50%的區(qū)域或者更多那么被判定為humongous。分配humongous連續(xù)的空間。你可以想象一下,如果G1在Young代分配humongous,而且它們存活很長時(shí)間,然后它們需要一些必要而且昂貴(記住H-obj連續(xù)的region)的操作,復(fù)制這些H-obj導(dǎo)survivor空間,最終這些H-obj升遷到Old代。因此,為了避免上面的操作,H-obj直接分配在Old代,然后分類整理,映射作為humongousregion。
通過在Old代直接分配H-obj,G1避免在任何evacuation階段包含它們,它們因此也不用移動(dòng)。Full GC期間,壓縮存活的H-obj。Full GC之后,multi-phased concurrent marking期間的清除階段 死亡的H-obj被回收。換句話說,H-obj在清除階段被回收,或者說它們在full gc期間被回收。
分配H-obj之前,G1 GC因?yàn)榉峙鋾?huì)交叉執(zhí)行檢查heap使用百分比,標(biāo)記的threshold。如果允許,G1 GC然后初始化concurrent marking周期。由于我們想避免evacuation failures和可能多的Full GC,這樣的方式被執(zhí)行。結(jié)果在沒有更過的可用region存活對象evacuations盡可能早檢查以便給G1盡量多的時(shí)間去完成并發(fā)周期。
對于G1 GC,基本前提是沒有太多H-obj和他們存活時(shí)間很長。然而,由于G1 GC的region尺寸取決于你的heap的 minimum值,它的發(fā)生建立在分配的region的尺寸上,你的humongous可以看上去"normal"分配。這會(huì)導(dǎo)致需要H-obj分配在Old代的region上,甚至?xí)?dǎo)致evacuation failure,因?yàn)镚1趕不上這些humongous分配。
現(xiàn)在你也許在思考如何找到humongous 分配導(dǎo)致evacuation failures的方法。這里,再一次-XX:+PrintAdaptiveSizePolicy會(huì)來到你的解決方案中。
你的GC日志中,可以看到類似下面的一些東西:
1361.680: [G1Ergonomics (Concurrent Cycles) request concurrent cycle initiation, reason: occupancy higher than threshold, occupancy: 1459617792 bytes, allocation request: 4194320 bytes, threshold: 1449551430 bytes (45.00 %), source: concurrent humongous allocation]
因此,你可以看到一次并發(fā)周期被要求發(fā)生由于humongous分配需要4194320 bytes。
這些信息是有用的,因此你不但被告知你的應(yīng)用有多少humongous分配(不管它們多還是少),而且還告訴你發(fā)配的大小。此外,如果你認(rèn)為過多humongous分配,你能做的就是增加G1的region尺寸作為適合humongous的規(guī)則尺寸。因此,例如,分配尺寸僅僅在4M之上。所以,為了讓這次分配可以規(guī)則分配,我們需要16M的region尺寸。所以,這里推薦明確設(shè)置命令行選項(xiàng):-XX:G1HeapRegionSize=16M。
Note:回想一下我上篇文章,G1 region 跨越1M-32M(2的指數(shù)),分配要求稍微超過4M。因此,8M的region的尺寸不足以避免humongous分配。問我們需要下一個(gè)2的指數(shù),16MB。
ok。我認(rèn)為這次我已經(jīng)講解了大部分重要問題和G1概念。再一次,謝謝閱讀!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/66367.html
摘要:原文出處設(shè)計(jì)的一個(gè)重要目標(biāo)是設(shè)置階段的持續(xù)時(shí)長和頻率,因?yàn)槔占骺深A(yù)測,可配置。收集器盡自己最大努力高概率實(shí)現(xiàn)目標(biāo)但不是必然,它會(huì)是硬實(shí)時(shí)。因此名稱是收集器。運(yùn)行不同使用獨(dú)立的收集器。 原文出處:G1 – Garbage First G1設(shè)計(jì)的一個(gè)重要目標(biāo)是設(shè)置stop-the-world階段的持續(xù)時(shí)長和頻率,因?yàn)槔占骺深A(yù)測,可配置。事實(shí)上,G1是一款軟實(shí)時(shí)的收集器,意味著你...
摘要:之前根據(jù)的內(nèi)存管理白皮書介紹了在分代算法中的幾個(gè)垃圾收集器,本文將介紹垃圾收集器。本節(jié)介紹的收集過程,收集器主要包括了以下種操作年輕代收集并發(fā)收集,和應(yīng)用線程同時(shí)執(zhí)行混合式垃圾收集必要時(shí)的接下來,我們進(jìn)行一一介紹。 之前根據(jù) Sun 的內(nèi)存管理白皮書介紹了在 HotSpot JVM 分代算法中的幾個(gè)垃圾收集器,本文將介紹 G1 垃圾收集器。 G1 的主要關(guān)注點(diǎn)在于達(dá)到可控的停頓時(shí)間,在...
摘要:垃圾收集器簡述全文共兩部分有基礎(chǔ)的讀者只需要閱讀第一部分垃圾收集器在最新幾個(gè)版本的發(fā)展第二部分為基礎(chǔ)部分垃圾收集器在最新幾個(gè)版本的發(fā)展垃圾收集器始見于版本在后續(xù)的幾個(gè)版本中對它進(jìn)行了優(yōu)化和改進(jìn)在中垃圾收集器增加了幾個(gè)可配置選項(xiàng)的自動(dòng)發(fā)現(xiàn)功能 G1垃圾收集器簡述 全文共兩部分,有基礎(chǔ)的讀者只需要閱讀第一部分G1垃圾收集器在最新幾個(gè)版本的發(fā)展,第二部分為基礎(chǔ)部分. G1垃圾收集器在最新幾個(gè)...
摘要:本文將會(huì)深入分析的引擎的內(nèi)部實(shí)現(xiàn)。該引擎使用在谷歌瀏覽器內(nèi)部。同其他現(xiàn)代引擎如或所做的一樣,通過實(shí)現(xiàn)即時(shí)編譯器在執(zhí)行時(shí)將代碼編譯成機(jī)器代碼。這可使正常執(zhí)行期間只發(fā)生相當(dāng)短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開始了一個(gè)系列博文旨在深入...
摘要:表示允許垃圾收集線程處理本次垃圾收集開始前沒有處理好的日志緩沖區(qū),這可以確保當(dāng)前分區(qū)的是最新的。垃圾收集線程在完成其他任務(wù)的時(shí)間展示每個(gè)垃圾收集線程的最小最大平均差值和總共時(shí)間。 本文翻譯自:https://www.redhat.com/en/blog/collecting-and-reading-g1-garbage-collector-logs-part-2?source=auth...
閱讀 2775·2019-08-30 15:55
閱讀 1873·2019-08-30 15:53
閱讀 2735·2019-08-29 18:38
閱讀 983·2019-08-26 13:49
閱讀 552·2019-08-23 15:42
閱讀 3269·2019-08-22 16:33
閱讀 1064·2019-08-21 17:59
閱讀 1150·2019-08-21 17:11