日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

G1 GC技术解析

發(fā)布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 G1 GC技术解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

介紹

????G1 GC,全稱Garbage-First Garbage Collector,通過-XX:+UseG1GC參數(shù)來啟用。G1收集器是工作在堆內(nèi)不同分區(qū)上的收集器,分區(qū)既可以是年輕代也可以是老年代,同一個代的分區(qū)不需要連續(xù)。并且每個代分區(qū)的數(shù)量是可以動態(tài)調(diào)整的。為老年代設(shè)置分區(qū)的目的是老年代里有的分區(qū)垃圾多,有的分區(qū)垃圾少,這樣在回收的時候可以專注于收集垃圾多的分區(qū),這也是G1名稱的由來。不過這個算法并不適合新生代垃圾收集,因為新生代的垃圾收集算法是復制算法,但是新生代也使用了分區(qū)機制主要是因為便于代大小的調(diào)整。
????G1 GC是設(shè)計用來取代CMS的,同CMS相比G1有以下優(yōu)勢:
1、可預(yù)測的停頓模型
2、避免了CMS的垃圾碎片
3、超大堆的表現(xiàn)更出色

G1關(guān)鍵概念

Region

????G1里面的Region的概念不同于傳統(tǒng)的垃圾回收算法中的分區(qū)的概念。G1默認把堆內(nèi)存分為2048個分區(qū),后續(xù)垃圾收集的單位都是以Region為單位的。Region是實現(xiàn)G1算法的基礎(chǔ),每個Region的大小相等,通過-XX:G1HeapRegionSize參數(shù)可以設(shè)置Region的大小。如下圖所示:



圖中的E代表是Eden區(qū),S代表Survivor,O代表Old區(qū),H代表humongous表示巨型對象(大小大小Region空間一半的對象)。從圖中可以看出各個區(qū)域邏輯上并不是連續(xù)的。并且一個Region在某一個時刻是Eden,在另一個時刻就可能屬于老年代。G1在進行垃圾清理的時候就是將一個Region的對象拷貝到另外一個Region中。

SATB

SATB的全稱是Snapchat-At-The_Beginning。SATB是維持并發(fā)GC的一種手段。G1并發(fā)的基礎(chǔ)就是SATB。SATB可以理解成在GC開始之前對堆內(nèi)存里的對象做一次快照,此時活的對象就認為是活的,從而形成一個對象圖。在GC收集的時候,新生代的對象也認為是活的對象,除此之外其他不可達的對象都認為是垃圾對象。
如何找到在GC的過程中分配的對象呢?每個region記錄著兩個top-at-mark-start(TAMS)指針,分別為prevTAMS和nextTAMS。在TAMS以上的對象就是新分配的,因而被視為隱式marked。通過這種方式我們就找到了在GC過程中新分配的對象,并把這些對象認為是活的對象。
解決了對象在GC過程中分配的問題,那么在GC過程中引用發(fā)生變化的問題怎么解決呢, G1給出的解決辦法是通過Write Barrier。Write Barrier就是對引用字段進行賦值做了環(huán)切。通過Write Barrier就可以了解到哪些引用對象發(fā)生了什么樣的變化。

RSet

RSet全稱是Remember Set,每個Region中都有一個RSet,記錄的是其他Region中的對象引用本Region對象的關(guān)系(誰引用了我的對象)。G1里面還有另外一種數(shù)據(jù)結(jié)構(gòu)就Collection Set(CSet),CSet記錄的是GC要收集的Region的集合,CSet里的Region可以是任意代的。在GC的時候,對于old->young和old->old的跨代對象引用,只要掃描對應(yīng)的CSet中的RSet即可。

停頓預(yù)測模型

G1收集器突出表現(xiàn)出來的一點是通過一個停頓預(yù)測模型來根據(jù)用戶配置的停頓時間來選擇CSet的大小,從而達到用戶期待的應(yīng)用程序暫停時間。通過-XX:MaxGCPauseMillis參數(shù)來設(shè)置。這一點有點類似于ParallelScavenge收集器。關(guān)于停頓時間的設(shè)置并不是越短越好。設(shè)置的時間越短意味著每次收集的CSet越小,導致垃圾逐步積累變多,最終不得不退化成Serial GC;停頓時間設(shè)置的過長,那么會導致每次都會產(chǎn)生長時間的停頓,影響了程序?qū)ν獾捻憫?yīng)時間。

#G1回收的過程
G1垃圾回收分為兩個階段:
1、全局并發(fā)標記階段(Global Concurrent marking)
2、拷貝存活對象階段(evacuation)

全局并發(fā)標記階段

????全局并發(fā)標記階段是基于SATB的,與CMS有些類似,但是也有不同的地方,主要的幾個階段如下:
初始標記:該階段會STW。掃描根集合,將所有通過根集合直達的對象壓入掃描棧,等待后續(xù)的處理。在G1中初始標記階段是借助Young GC的暫停進行的,不需要額外的暫停。雖然加長了Young GC的暫停時間,但是從總體上來說還是提高的GC的效率。
并發(fā)標記:該階段不需要STW。這個階段不斷的從掃描棧中取出對象進行掃描,將掃描到的對象的字段再壓入掃描棧中,依次遞歸,直到掃描棧為空,也就是說trace了所有GCRoot直達的對象。同時這個階段還會掃描SATB write barrier所記錄下的引用。
最終標記:也叫Remark,這個階段也是STW的。這個階段會處理在并發(fā)標記階段write barrier記錄下的引用,同時進行弱引用的處理。這個階段與CMS的最大的區(qū)別是CMS在這個階段會掃描整個根集合,Eden也會作為根集合的一部分被掃描,因此耗時可能會很長。
清理:?該階段會STW。清點和重置標記狀態(tài)。這個階段有點像mark-sweep中的sweep階段,這個階段并不會實際上去做垃圾的收集,只是去根據(jù)停頓模型來預(yù)測出CSet,等待evacuation階段來回收。

拷貝存活對象階段

????Evacuation階段是全暫停的。該階段把一部分Region里的活對象拷貝到另一部分Region中,從而實現(xiàn)垃圾的回收清理。Evacuation階段從第一階段選出來的Region中篩選出任意多個Region作為垃圾收集的目標,這些要收集的Region叫CSet,通過RSet實現(xiàn)。
篩選出CSet之后,G1將并行的將這些Region里的存活對象拷貝到其他Region中,這點類似于ParalledScavenge的拷貝過程,整個過程是完全暫停的。關(guān)于停頓時間的控制,就是通過選擇CSet的數(shù)量來達到控制時間長短的目標。

G1的收集模式:

YoungGC:收集年輕代里的Region
MixGC:年輕代的所有Region+全局并發(fā)標記階段選出的收益高的Region
無論是YoungGC還是MixGC都只是并發(fā)拷貝的階段。

分代G1模式下選擇CSet有兩種子模式,分別對應(yīng)YoungGC和mixedGC:
YoungGC:CSet就是所有年輕代里面的Region
MixedGC:CSet是所有年輕代里的Region加上在全局并發(fā)標記階段標記出來的收益高的Region

????G1的運行過程是這樣的,會在Young GC和Mix GC之間不斷的切換運行,同時定期的做全局并發(fā)標記,在實在趕不上回收速度的情況下使用Full GC(Serial GC)。初始標記是搭在YoungGC上執(zhí)行的,在進行全局并發(fā)標記的時候不會做Mix GC,在做Mix GC的時候也不會啟動初始標記階段。當MixGC趕不上對象產(chǎn)生的速度的時候就退化成Full GC,這一點是需要重點調(diào)優(yōu)的地方。

G1最佳實踐

????在使用G1垃圾收集器的時候遵循以下實踐可以少走不少彎路:

不斷調(diào)優(yōu)暫停時間指標

????通過XX:MaxGCPauseMillis=x可以設(shè)置啟動應(yīng)用程序暫停的時間,G1在運行的時候會根據(jù)這個參數(shù)選擇CSet來滿足響應(yīng)時間的設(shè)置。一般情況下這個值設(shè)置到100ms或者200ms都是可以的(不同情況下會不一樣),但如果設(shè)置成50ms就不太合理。暫停時間設(shè)置的太短,就會導致出現(xiàn)G1跟不上垃圾產(chǎn)生的速度。最終退化成Full GC。所以對這個參數(shù)的調(diào)優(yōu)是一個持續(xù)的過程,逐步調(diào)整到最佳狀態(tài)。

不要設(shè)置新生代和老年代的大小

????G1收集器在運行的時候會調(diào)整新生代和老年代的大小。通過改變代的大小來調(diào)整對象晉升的速度以及晉升年齡,從而達到我們?yōu)槭占髟O(shè)置的暫停時間目標。設(shè)置了新生代大小相當于放棄了G1為我們做的自動調(diào)優(yōu)。我們需要做的只是設(shè)置整個堆內(nèi)存的大小,剩下的交給G1自己去分配各個代的大小。

關(guān)注Evacuation Failure

Evacuation Failure類似于CMS里面的晉升失敗,堆空間的垃圾太多導致無法完成Region之間的拷貝,于是不得不退化成Full GC來做一次全局范圍內(nèi)的垃圾收集。

G1常用參數(shù)

參數(shù)/默認值 含義

-XX:+UseG1GC使用 G1 垃圾收集器
-XX:MaxGCPauseMillis=200設(shè)置期望達到的最大GC停頓時間指標(JVM會盡力實現(xiàn),但不保證達到)
-XX:InitiatingHeapOccupancyPercent=45啟動并發(fā)GC周期時的堆內(nèi)存占用百分比. G1之類的垃圾收集器用它來觸發(fā)并發(fā)GC周期,基于整個堆的使用率,而不只是某一代內(nèi)存的使用比. 值為 0 則表示”一直執(zhí)行GC循環(huán)”. 默認值為 45.
-XX:NewRatio=n新生代與老生代(new/old generation)的大小比例(Ratio). 默認值為 2.
-XX:SurvivorRatio=neden/survivor 空間大小的比例(Ratio). 默認值為 8.
-XX:MaxTenuringThreshold=n提升年老代的最大臨界值(tenuring threshold). 默認值為 15.
-XX:ParallelGCThreads=n設(shè)置垃圾收集器在并行階段使用的線程數(shù),默認值隨JVM運行的平臺不同而不同.
-XX:ConcGCThreads=n并發(fā)垃圾收集器使用的線程數(shù)量. 默認值隨JVM運行的平臺不同而不同.
-XX:G1ReservePercent=n設(shè)置堆內(nèi)存保留為假天花板的總量,以降低提升失敗的可能性. 默認值是 10.
-XX:G1HeapRegionSize=n使用G1時Java堆會被分為大小統(tǒng)一的的區(qū)(region)。此參數(shù)可以指定每個heap區(qū)的大小. 默認值將根據(jù) heap size 算出最優(yōu)解. 最小值為 1Mb, 最大值為 32Mb.

G1日志分析

//新生代GC 2018-05-03T10:21:43.209-0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0035356 secs] //初始標記,耗時0.0035秒[Parallel Time: 2.4 ms, GC Workers: 8] //并行8個線程,耗時2.4ms[GC Worker Start (ms): Min: 813.1, Avg: 813.7, Max: 813.9, Diff: 0.7][Ext Root Scanning (ms): Min: 0.0, Avg: 1.1, Max: 1.5, Diff: 1.5, Sum: 9.1] //每個掃描root的線程耗時[Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] //更新RS的耗時,G1中每塊區(qū)域都有一個RS與之對應(yīng),RS記錄了該區(qū)域被其他區(qū)域引用的對象。回收時,就把RS作為根集的一部分,從而加快回收[Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0] //Processed Buffers就是記錄引用變化的緩存空間[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] //掃描RS[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] //根掃描耗時[Object Copy (ms): Min: 0.0, Avg: 0.5, Max: 1.3, Diff: 1.3, Sum: 3.6] //對象拷貝[Termination (ms): Min: 0.0, Avg: 0.2, Max: 0.2, Diff: 0.2, Sum: 1.2] [Termination Attempts: Min: 1, Avg: 1.8, Max: 4, Diff: 3, Sum: 14][GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1][GC Worker Total (ms): Min: 1.6, Avg: 1.8, Max: 2.3, Diff: 0.8, Sum: 14.1] //GC線程耗時[GC Worker End (ms): Min: 815.4, Avg: 815.4, Max: 815.4, Diff: 0.0][Code Root Fixup: 0.0 ms][Code Root Purge: 0.0 ms][Clear CT: 0.1 ms] //清空CardTable耗時,RS是依賴CardTable記錄區(qū)域存活對象的[Other: 1.1 ms][Choose CSet: 0.0 ms] //選取CSet[Ref Proc: 0.9 ms] //弱引用、軟引用的處理耗時[Ref Enq: 0.0 ms] //弱引用、軟引用的入隊耗時[Redirty Cards: 0.1 ms][Humongous Register: 0.0 ms][Humongous Reclaim: 0.0 ms][Free CSet: 0.0 ms] //釋放被回收區(qū)域的耗時(包含他們的RS)[Eden: 5120.0K(24.0M)->0.0B(12.0M) Survivors: 0.0B->2048.0K Heap: 16.0M(50.0M)->12.4M(50.0M)][Times: user=0.01 sys=0.00, real=0.01 secs] //根區(qū)域掃描 2018-05-03T10:21:43.213-0800: [GC concurrent-root-region-scan-start] 2018-05-03T10:21:43.214-0800: [GC concurrent-root-region-scan-end, 0.0012422 secs] // 并發(fā)標記 2018-05-03T10:21:43.214-0800: [GC concurrent-mark-start] 2018-05-03T10:21:43.214-0800: [GC concurrent-mark-end, 0.0004063 secs] //重新標記又叫最終標記 2018-05-03T10:21:43.214-0800: [GC remark 2018-05-03T10:21:43.215-0800: [Finalize Marking, 0.0003736 secs] 2018-05-03T10:21:43.215-0800: [GC ref-proc, 0.0000533 secs] 2018-05-03T10:21:43.215-0800: [Unloading, 0.0007439 secs], 0.0013442 secs][Times: user=0.00 sys=0.00, real=0.00 secs] //獨占清理 2018-05-03T10:21:43.216-0800: [GC cleanup 13M->13M(50M), 0.0004002 secs][Times: user=0.01 sys=0.00, real=0.00 secs]


? ? 這是一段完整的GC日志。從整體上看,并發(fā)標記周期和混合回收的前后都有可能穿插著新生代GC。其中并發(fā)標記周期主要是回收老年代空間,當然也包含了一次新生代GC。?

總結(jié)

以上是生活随笔為你收集整理的G1 GC技术解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。