溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java中的G1回收器怎么用

發(fā)布時(shí)間:2021-09-27 09:55:41 來源:億速云 閱讀:131 作者:柒染 欄目:編程語言

這篇文章給大家介紹java中的G1回收器怎么用,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

G1 回收器

G1回收器是在jdk1.7中正式使用的全新垃圾回收器,并且是jdk9及之后版本的默認(rèn)回收器。從分代上看,G1 依然屬于分代垃圾回收器,它會(huì)區(qū)分年輕代和老年代,依然有eden區(qū)和survivor區(qū),但從堆的結(jié)構(gòu)上看,它并不要求整個(gè)eden區(qū)、年輕代或者老年代都連續(xù)。G1使用了全新的分區(qū)算法,特點(diǎn)如下:

  • 并行性:G1在回收期間,可以由多個(gè)GC線程同時(shí)工作,有效利用多核計(jì)算能力。

  • 并發(fā)性:G1在擁有與應(yīng)用程序交替執(zhí)行的能力,部分工作可以和應(yīng)用程序同時(shí)執(zhí)行,一般來說,不會(huì)在整個(gè)回收期間完全阻塞應(yīng)用程序。

  • 分代GC:G1依然是一個(gè)分代回收器,但是和之前的回收器不同,它同時(shí)兼顧年輕代和老年代,其他回收器或者工作在年輕代,或者工作在老年代。

  • 空間整理:G1在回收過程中,會(huì)進(jìn)行適當(dāng)?shù)膶ο笠苿?dòng),不像CMS,只是簡單地標(biāo)記清理對象,在若干次GC后,CMS必須進(jìn)行一次碎片整理。而G1不同,它每次回收都會(huì)有效地復(fù)制對象,減少碎片空間。

  • 可預(yù)見性:由于分區(qū)的原因,G1可以只選取部分區(qū)域進(jìn)行內(nèi)存回收,這樣縮小了回收的范圍,全局停頓也能得到較好的控制。

1 G1的內(nèi)存劃分和主要收集過程

G1將堆進(jìn)行分區(qū),劃分為一個(gè)個(gè)的區(qū)域,每次回收時(shí),只回收其中幾個(gè)區(qū)域,以此來控制垃圾回收產(chǎn)生的一次停頓時(shí)間。

G1的回收過程可能有4個(gè)階段:

  • 新生代GC

  • 并發(fā)標(biāo)記周期

  • 混合回收

  • 如果需要,可能會(huì)進(jìn)行FullGC

2. G1的新生代GC

新生代GC的主要工作是回收eden區(qū)和survivor區(qū)。一旦eden區(qū)被占滿,新生代GC就會(huì)啟動(dòng)。新生代GC只處理eden區(qū)和survivor區(qū),回收后所有的eden區(qū)都應(yīng)該被清空,而survivor區(qū)會(huì)被回收一部分?jǐn)?shù)據(jù)。

3. G1 的并發(fā)標(biāo)記周期

G1 的并發(fā)階段和 CMS 有點(diǎn)類似,它們都是為了降低一次停頓時(shí)間,而將可以和應(yīng)用程序并發(fā)的部分單獨(dú)提取出來執(zhí)行。

并發(fā)標(biāo)記周期可以分為以下幾步:

  • 初始標(biāo)記:標(biāo)記從根節(jié)點(diǎn)直接可達(dá)的對象。這個(gè)階段會(huì)伴隨一次新生代GC,它是產(chǎn)生全局停頓的,應(yīng)用程序線程在這個(gè)階段必須停止執(zhí)行。

  • 根區(qū)域掃描:由于初始標(biāo)記必然會(huì)伴隨一次新生代GC,所以在初始化標(biāo)記后,eden區(qū)被清空,并且存活對象被移入survivor區(qū)。在這個(gè)階段,將掃描由survivor區(qū)直接可達(dá)的老年代區(qū)域,并標(biāo)記這些直接可達(dá)的對象。這個(gè)過程是可以和應(yīng)用程序并發(fā)執(zhí)行的,但是根區(qū)域掃描不能和新生代GC同時(shí)執(zhí)行,因?yàn)槿绻∏稍诖藭r(shí)需要進(jìn)行新生代GC,就需要等待根區(qū)域掃描結(jié)束后才能進(jìn)行。如果發(fā)生這種情況,這次新生代GC的時(shí)間就會(huì)延長。

  • 并發(fā)標(biāo)記:和CMS類似,并發(fā)標(biāo)記將會(huì)掃描并查找整個(gè)堆的存活對象,并做好標(biāo)記。這是一個(gè)并發(fā)的過程,并且這個(gè)過程可以被一次新生代GC打斷。

  • 重新標(biāo)記:和CMS一樣,重新標(biāo)記也是會(huì)產(chǎn)生應(yīng)用程序停頓的。由于并發(fā)標(biāo)記過程中,應(yīng)用程序依然在運(yùn)行,因此標(biāo)記結(jié)果可能需要修正,所以在此對上一次的標(biāo)記結(jié)果進(jìn)行補(bǔ)充。在 G1 中,這個(gè)過程使用SATB(Snapshot-At-The-Beginning)算法完成,即G1會(huì)在標(biāo)記之初為存活對象創(chuàng)建一個(gè)快照,這個(gè)快照有助于加速重新標(biāo)記的速度。

  • 獨(dú)占清理:這個(gè)階段是會(huì)引起停頓的。它將計(jì)算各個(gè)區(qū)域的存活對象和GC回收比例,并進(jìn)行排序,識(shí)別可供混合回收的區(qū)域。識(shí)別可供混合回收的區(qū)域。在這個(gè)階段,還會(huì)更新記憶集(Remebered Set)。該階段給出了需要被混合回收的區(qū)域并進(jìn)行了標(biāo)記,在混合回收階段需要這些信息。

  • 并發(fā)清理:這里會(huì)識(shí)別并清理完全空閑的區(qū)域。它是并發(fā)的清理,不會(huì)引起停頓。

除了初始標(biāo)記、重新標(biāo)記獨(dú)占清理,其他幾個(gè)階段都可以和應(yīng)用程序并發(fā)執(zhí)行。

在并發(fā)標(biāo)記周期中,G1會(huì)產(chǎn)生如下日志:

3.1 初始標(biāo)記,它伴隨著一次新生代GC
[GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0014636 secs]
   ...
   [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
 [Times: user=0.01 sys=0.00, real=0.00 secs]
3.2 一次并發(fā)的根區(qū)域掃描,并發(fā)掃描過程中不能被新生代GC中斷。
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0003832 secs]
3.3 并發(fā)標(biāo)記,并發(fā)標(biāo)記可以被新生代GC打斷,下面的日志顯示了一次并發(fā)標(biāo)記被3次新生代GC打斷。
[GC concurrent-mark-start]
[GC pause (young), 0.0003382 secs]
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC concurrent-mark-end, 0.0003929 secs]
3.4 重新標(biāo)記:是會(huì)引起全局停頓的,它的日志如下:
[GC remark [Finalize Marking, 0.0006027 secs] [GC ref-proc, 0.0000295 secs] [Unloading, 0.0003390 secs], 0.0010737 secs]
 [Times: user=0.01 sys=0.00, real=0.01 secs]
3.5 重新標(biāo)記后會(huì)進(jìn)行獨(dú)占清理,獨(dú)占清理會(huì)重新計(jì)算各個(gè)區(qū)域的存活對象,并以此可以得到每個(gè)區(qū)域進(jìn)行GC的效果,它的日志如下:
[GC cleanup 10M->10M(40M), 0.0003016 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
3.6 并發(fā)清理,是并發(fā)執(zhí)行的,它會(huì)根據(jù)獨(dú)占清理階段計(jì)算得出每個(gè)區(qū)域的存活對象數(shù)量,直接回收不包含存活對象的區(qū)域。它的日志如下:
[GC concurrent-cleanup-start]
[GC concurrent-cleanup-end, 0.0000016 secs]

4. 混合回收

在并發(fā)標(biāo)記周期中,雖然有部分對象被回收,但是總體上說,回收的比例是相當(dāng)?shù)偷摹5窃诓l(fā)標(biāo)記周期后,G1已經(jīng)明確知道哪些區(qū)域含有比較多的垃圾對象,在混合回收階段就可以專門針對這些區(qū)域進(jìn)行回收。這個(gè)階段叫做混合回收,是因?yàn)檫@個(gè)階段既會(huì)執(zhí)行正常的年輕代GC,又會(huì)選取一些被標(biāo)記的老年代區(qū)域進(jìn)行回收,它同時(shí)處理了新生代和老年代。

混合GC會(huì)產(chǎn)生如下日志:

[GC pause (mixed), 0.0003382 secs]
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs]

混合GC會(huì)執(zhí)行多次,走到回收了足夠多的內(nèi)存空間,然后它會(huì)觸發(fā)一次新生代GC。新生代GC后,又可難會(huì)發(fā)生一次并發(fā)標(biāo)記周期的處理,最后又會(huì)引起混合GC的執(zhí)行。

5. 必要時(shí)的Full GC

和CMS類似,并發(fā)回收由于讓應(yīng)用程序和GC線程交替工作,總是不能完全避免在特別繁忙的場合出現(xiàn)在回收過程中內(nèi)存不充足的情況。當(dāng)遇到這種情況時(shí),G1也會(huì)轉(zhuǎn)入一個(gè)FullGC。

當(dāng)G1在并發(fā)標(biāo)記時(shí),由于老年代被快速填充,G1會(huì)終止并發(fā)標(biāo)記而轉(zhuǎn)入一個(gè)Full GC:

[GC concurrent-mark-start]
[Full GC 898->896(900M), 0.7003382 secs]
  [Eden: 0K(45.0M)->0.0B(45.0M) Survivors: 0.0B->0B Heap: 898.7M(900.0M)->896.2M(900.0M)]
[Times: user=1.01 sys=0.00, real=0.075 secs] 
[GC concurrent-mark-abort]

此外,如果在混合GC時(shí)空間不足,或者在新生代GC時(shí)survivor區(qū)和老年代無法容納幸存對象,都會(huì)導(dǎo)致一次FullGC.

6. G1的日志

# 表示應(yīng)用程序發(fā)生了一次新生代GC,這是在初始標(biāo)記時(shí)發(fā)生的,耗時(shí)0.0018193秒,意味著程序至少暫停了0.0018193秒
[GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0018193 secs]
   # 后續(xù)并行時(shí)間,表示所有GC線程總的花費(fèi)時(shí)間,這里為0.9毫秒,workers為8表示有8個(gè)GC線程
   [Parallel Time: 0.9 ms, GC Workers: 8]
      # GC線程的執(zhí)行情況,這里統(tǒng)計(jì)了8個(gè)線程的統(tǒng)計(jì)值,如 平均、最小、最大和差值(最大值與最小值之差),
      # 106.6 表示在應(yīng)用程序啟動(dòng) 106.6 毫秒后,啟動(dòng)了該GC線程
      [GC Worker Start (ms): Min: 106.6, Avg: 106.7, Max: 106.7, Diff: 0.1]
      # 根掃描時(shí)間的統(tǒng)計(jì)值
      [Ext Root Scanning (ms): Min: 0.4, Avg: 0.4, Max: 0.5, Diff: 0.1, Sum: 3.3]
      # 更新記憶集(Remember Set)的耗時(shí)。
      # 記憶集是G1中維護(hù)的一個(gè)數(shù)據(jù)結(jié)構(gòu),簡稱RS。每一個(gè)G1區(qū)域都有一個(gè)RS與之關(guān)聯(lián)。由于G1回收時(shí)是按照區(qū)域
      # 回收的,比如在回收區(qū)域A的對象時(shí),很可能并不回收區(qū)域B的對象,為了回收區(qū)域A的對象,要掃描區(qū)域B甚
      # 至整個(gè)堆來判定區(qū)域A中哪些對象不可達(dá),這樣做的代價(jià)顯然很大。因此,G1在區(qū)域A的RS中,記錄了在區(qū)域
      # A中被其他區(qū)域引用的對象,這樣在回收區(qū)域A時(shí),只要將RS視為區(qū)域A根集的一部分即可,從而避免做整個(gè)堆
      # 的的掃描。由于系統(tǒng)在運(yùn)行過程中,對象之間的引用關(guān)系是可能時(shí)刻變化的,為了更高效地跟蹤這些引用關(guān)系,
      # 會(huì)將這些變化記錄在Update Buffers中。這里的Processed Buffers指的就是處理這個(gè)Update Buffers數(shù)據(jù)。
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
      # 掃描RS的時(shí)間 
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      # 在正式回收前,G1 會(huì)對被回收區(qū)域的對象進(jìn)行疏散,即將存活對象放置在其他區(qū)域中,因此需要進(jìn)行對象復(fù)制
      [Object Copy (ms): Min: 0.2, Avg: 0.3, Max: 0.4, Diff: 0.2, Sum: 2.2]
      # 給出GC工程線程終止的信息,這里的終止時(shí)間是線程花在終止階段的耗時(shí)。在GC線程終止前,它們會(huì)檢查其
      # 他GC線程的工作隊(duì)列,查看是否仍然還有對象引用沒有處理完,如果其他線程仍然有沒有處理完的數(shù)據(jù),請求
      # 終止的線程會(huì)幫助它盡快完成,隨后再嘗試終止。其中,Termination Attempts 展示了工作線程的終止次數(shù)。
      [Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 1.0]
         [Termination Attempts: Min: 1, Avg: 2.9, Max: 6, Diff: 5, Sum: 23]
      # 顯示GC線程花費(fèi)在其他任務(wù)中的耗時(shí)
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 0.8, Avg: 0.8, Max: 0.9, Diff: 0.1, Sum: 6.6]
      # GC 工作線程的完成時(shí)間
      [GC Worker End (ms): Min: 107.5, Avg: 107.5, Max: 107.5, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   # 顯示清空 CardTable的時(shí)間,RS 就是依靠CardTable來記錄哪些是存活對象的
   [Clear CT: 0.1 ms]
   # 顯示其他幾個(gè)任務(wù)的耗時(shí),比如選擇CSet(Collection Sets,表示被選取的、將要被回收的區(qū)域的集合)的時(shí)
   # 間、Ref Proc(處理弱引用、軟引用的時(shí)間)、Ref End(弱引用、軟引用入隊(duì)時(shí)間)和Free CSet(釋放被
   # 回收的CSet中區(qū)域的時(shí)間,包括它們的RS)
   [Other: 0.8 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.7 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]
   [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2656.1K(40.0M)]
 [Times: user=0.00 sys=0.00, real=0.00 secs]

7. 相關(guān)的參數(shù)

  • -XX:+UseG1GC:啟用G1回收器

  • -XX:MaxGCPauseMillis: 用于指定目標(biāo)最大停頓時(shí)間。如果任何一次停頓時(shí)間超過這個(gè)設(shè)置值,G1就會(huì)嘗試調(diào)整新生代和老年代的比例、調(diào)整堆大小、調(diào)整晉升年齡等,試圖達(dá)到預(yù)設(shè)目標(biāo)。對于性能調(diào)優(yōu)來說,總是魚和熊掌不可兼得,如果停頓時(shí)間縮短,對于新生代來說,意味著很可能要增加新生代GC的次數(shù)。對于老年代來說,為了獲得短暫的停頓時(shí)間,在混合GC時(shí),一次收集的區(qū)域數(shù)量也會(huì)變少,這樣無疑增加了進(jìn)行FullGC的可能性。

  • -XX:ParallelGCThreads: 設(shè)置并行回收時(shí)GC的工作線程數(shù)量。

  • -XX:InitatingHeapOccupancyPercent: 指定當(dāng)整個(gè)堆使用率達(dá)到多少時(shí),觸發(fā)并發(fā)標(biāo)記周期的執(zhí)行,默認(rèn)值是45.InitatingHeapOccupancyPercent一旦設(shè)置,始終都不會(huì)被G1修改,這意味著G1不會(huì)試圖改變這個(gè)值來滿足MaxGCPauseMillis 的目標(biāo),那么引起FullGC的可能性也大大增加,反之,一個(gè)過小的InitatingHeapOccupancyPercent值會(huì)使得并發(fā)標(biāo)記周期執(zhí)行非常頻繁,大量GC線程搶占CPU,導(dǎo)致應(yīng)用程序的性能有所下降。

關(guān)于java中的G1回收器怎么用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI