JVM G1(Garbage-First Garbage Collector)收集器全過程剖析

G1垃圾收集器的設計原則是「首先收集儘量多的垃圾(Garbage First)」,目標是爲了儘可能縮短處理超大堆(超過4GB)產生的停頓。html

所以,G1並不會等內存耗盡(好比Serial 串行收集器、Parallel並行收集器 )者快耗盡(CMS)的時候纔開始垃圾回收,而是在內部採用了啓發式算法,在老年代中找出具備高收集收益的分區(Region)進行收集。java

同時 G1 能夠根據用戶設置的STW(Stop-The-World)停頓時間目標(響應時間優先)自動調全年輕代和總堆的大小,停頓時間越短年輕代空間就可能越小,總堆空間越大。web

G1相對於CMS一個比較明顯的優點是,內存碎片的產生率大大下降。算法

G1在 JDK7u4以上均可以使用,在JDK9開始,G1爲默認的垃圾收集器,以替代CMSshell

G1算法

算法:三色標記 + SATBbash

G1的特性

  • 面向服務端應用的垃圾收集器
  • 並行與併發:G1能充分利用多CPU、多核環境使用多個CPU或CPU核心來縮短STW(Stop-The-World)停頓時間。
  • 分代收集:G1物理上不分代,但邏輯上仍然有分代的概念。
  • 空間整合:不會產生內存空間碎片,收集後可提供規整的可用內存,整理空閒空間更快。
  • 可預測的停頓(它能夠有計劃的避免在整個JAVA堆中進行全區域的垃圾收集)
  • 適用於不須要實現很高吞吐量的場景
  • JAVA堆內存佈局與其它收集器存在很大差異,它將整個JAVA堆劃分爲多個大小相等的獨立區域或分區(Region)。
  • G1收集器中,虛擬機使用Remembered Set來避免全堆掃描。

G1的內存模型

分區概念

傳統的GC收集器將連續的內存空間劃分爲新生代、老年代和永久代(JDK 8去除了永久代,引入了元空間Metaspace),數據結構

這種劃分的特色是各代的存儲地址(邏輯地址,下同)是連續的。以下圖所示:多線程

而G1的各代存儲地址是不連續的,每一代都使用了n個不連續的大小相同的Region,每一個Region佔有一塊連續的虛擬內存地址。併發

Region (區域,分區)

G1採用了分區(Region)的思路,將整個堆空間分紅若干個大小相等的內存區域,每次分配對象空間將逐段地使用內存。oracle

雖然還保留了新生代和老年代的概念,但新生代和老年代再也不是物理隔離,它們都是一部分Region(不須要連續)的集合。

所以,在堆的使用上,G1並不要求對象的存儲必定是物理上連續的,只要邏輯上連續便可;

每一個分區Region也不會肯定地爲某個代服務,能夠按需在年輕代和老年代之間切換。

啓動時能夠經過參數-XX:G1HeapRegionSize=n可指定分區大小(1MB~32MB,且必須是2的冪),默認將整堆劃分爲2048個分區。

Card (卡片)

在每一個分區Region 內部又被分紅了若干個大小爲512 Byte卡片(Card),標識堆內存最小可用粒度。

全部分區Region 的卡片將會記錄在全局卡片表(Global Card Table)中。

分配的對象會佔用物理上連續的若干個卡片。

當查找對分區Region 內對象的引用時即可經過記錄卡片來查找該引用對象(見RSet)。

每次對內存的回收,都是對指定分區的卡片進行處理。

Heap (堆)

G1一樣能夠經過-Xms/-Xmx來指定堆空間大小。

當發生年輕代收集(YGC)或混合收集(Mixed GC)時,經過計算GC與應用的耗費時間比,自動調整堆空間大小。

若是GC頻率過高,則經過增長堆尺寸,來減小GC頻率,相應地GC佔用的時間也隨之下降;

目標參數-XX:GCTimeRatio即爲GC與應用的耗費時間比,G1默認爲12(JDK7,8爲99,JDK11+開始爲12),而CMS默認爲99,由於CMS的設計原則是耗費在GC上的時間儘量的少。

另外,當空間不足,如對象空間分配或轉移失敗時,G1會首先嚐試增長堆空間,若是擴容失敗,則發起擔保的Full GC

Full GC後,堆尺寸計算結果也會調整堆空間。

分代概念

Generation (分代 )

分代垃圾收集能夠將關注點集中在最近被分配的對象上,而無需整堆掃描,避免長命對象的拷貝,同時獨立收集有助於下降響應時間。

雖然分區使得內存分配再也不要求緊湊的內存空間,但G1依然使用了分代的思想。

與其餘垃圾收集器相似,G1將內存在邏輯上劃分爲年輕代和老年代,其中年輕代又劃分爲Eden空間和Survivor空間。

但年輕代空間並非固定不變的,當現有年輕代分區佔滿時,JVM會分配新的空閒分區加入到年輕代空間。

整個年輕代內存會在初始空間-XX:NewSize與最大空間-XX:MaxNewSize之間動態變化,且由參數目標暫停時間-XX:MaxGCPauseMillis、須要擴縮容的大小以及分區的已記憶集合(RSet)計算獲得。

固然,G1依然能夠設置固定的年輕代大小(參數-XX:NewRatio-Xmn),但同時暫停目標將失去意義。

#####Local allocation buffer (LAB) (本地分配緩衝) 值得注意的是,因爲分區的思想,每一個線程都可以"認領"某個分區Region用於線程本地的內存分配,而不須要顧及分區是否連續。

所以,每一個應用線程和GC線程都會獨立的使用分區,進而減小同步時間,提高GC效率,這個分區Region稱爲本地分配緩衝區(LAB)。

  • 應用線程本地緩衝區TLAB: 應用線程能夠獨佔一個本地緩衝區(TLAB)來建立的對象,而大部分都會落入Eden區域(巨型對象或分配失敗除外),所以TLAB的分區屬於Eden空間;
  • GC線程本地緩衝區GCLAB: 每次垃圾收集時,每一個GC線程一樣能夠獨佔一個本地緩衝區(GCLAB)用來轉移對象,每次回收會將對象複製到Suvivor空間或老年代空間;
  • 晉升本地緩衝區PLAB: 對於從Eden/Survivor空間晉升(Promotion)到Survivor/老年代空間的對象,一樣有GC獨佔的本地緩衝區進行操做,該部分稱爲晉升本地緩衝區(PLAB)。

分區模型

Humongous Object (巨型對象)

一個大小達到甚至超過度區Region 50%以上的對象稱爲巨型對象(Humongous Object)。 巨型對象會獨佔一個、或多個連續分區,其中第一個分區被標記爲開始巨型(StartsHumongous),相鄰連續分區被標記爲連續巨型(ContinuesHumongous)。 Humongous Object 有如下特色:

  • Humongous Object直接分配到了 老年代,防止了反覆拷貝移動。

當線程爲巨型分配空間時,不能簡單在TLAB進行分配,由於巨型對象的移動成本很高,並且有可能一個分區不能容納巨型對象。 所以,巨型對象會直接在老年代分配,所佔用的連續空間稱爲巨型分區(Humongous Region)。

  • Humongous ObjectYGC階段, Global Concurrent Marking 階段的 CleanupFGC 階段 回收。

因爲沒法享受LAB帶來的優化,而且肯定一片連續的內存空間須要掃描整堆Heap,所以肯定巨型對象開始位置的成本很是高,若是能夠,應用程序應避免生成巨型對象。

  • 在分配Humongous Object 以前先檢查是否超過 initiating heap occupancy percent (由參數-XX:InitiatingHeapOccupancyPercent控制) 和 the marking threshold。 若是超過的話,就啓動併發收集週期Concurrent Marking Cycle ,爲的是提前回收,防止 Evacuation FailureFull GC
RSetRemember Set,已記憶集合)

在串行和並行收集器中,GC經過整堆掃描,來肯定對象是否處於可達路徑中。

然而G1爲了不STW式的整堆Heap掃描,在每一個分區Region記錄了一個已記憶集合(RSet),內部相似一個反向指針,記錄引用分區Region內對象的卡片Card的索引。

當要回收該分區Region時,經過掃描分區的RSet,來肯定引用本分區內的對象是否存活,進而肯定本分區內的對象存活狀況。

事實上,並不是全部的引用都須要記錄在RSet中,若是一個分區Region肯定須要掃描,那麼無需RSet也能夠無遺漏的獲得引用關係。

那麼引用源自本分區Region的對象,固然不用落入RSet中;

同時,G1 GC每次都會對年輕代進行總體收集,所以引用源自年輕代的對象,也不須要在RSet記錄。

最後只有老年代的分區Region可能會有RSet記錄,這些分區稱爲擁有RSet分區(an RSet’s owning region)。

Per Region Table (PRT)

RSet在內部使用Per Region Table(PRT)記錄分區Region的引用狀況。 因爲RSet的記錄要佔用分區Region的空間,若是一個分區很是"受歡迎",那麼RSet佔用的空間會上升,從而下降分區Region的可用空間。 G1應對這個問題採用了改變RSet的密度的方式,在PRT中將會以三種模式記錄引用:

  • 稀少:直接記錄引用對象的卡片Card的索引
  • 細粒度:記錄引用對象的分區Region的索引
  • 粗粒度:只記錄引用狀況,每一個分區對應一個比特位

由上可知,粗粒度的PRT只是記錄了引用數量,須要經過整堆Heap掃描才能找出全部引用,所以掃描速度也是最慢的。

CSetCollection Set,收集集合)

收集集合(CSet)表明每次GC暫停時回收的一系列目標分區Region

在任意一次收集暫停中,CSet全部分區都會被釋放,內部存活的對象都會被轉移到分配的空閒分區中。

所以不管是年輕代收集,仍是混合收集,工做的機制都是一致的。

年輕代收集(YGC)的CSet只容納年輕代分區,而混合收集(Mixed GC)會經過啓發式算法,在老年代候選回收分區中,篩選出回收收益最高的分區添加到CSet中。

  • 候選老年代分區的CSet准入條件,能夠經過活躍度閾值-XX:G1MixedGCLiveThresholdPercent(默認85%)進行設置,從而攔截那些回收開銷巨大的對象;

  • 同時,每次混合收集能夠包含候選老年代分區,可根據CSet對堆的總大小佔比-XX:G1OldCSetRegionThresholdPercent(默認10%)設置數量上限。

由上述可知,G1的收集都是根據CSet進行操做的,年輕代收集(YGC)與混合收集(Mixed GC)沒有明顯的不一樣,最大的區別在於兩種收集的觸發條件。

年輕代收集集合 CSet of Young Collection

應用線程不斷活動後,年輕代空間會被逐漸填滿。當JVM分配對象到Eden區域失敗(Eden區已滿)時,便會觸發一次STW式的年輕代收集。 在年輕代收集中,Eden分區存活的對象將被拷貝到Survivor分區; 原有Survivor分區存活的對象,將根據任期閾值(tenuring threshold)分別晉升到PLAB中,新的survivor分區和老年代分區。而原有的年輕代分區將被總體回收掉。

同時,年輕代收集還負責維護對象的年齡(存活次數),輔助判斷老化(tenuring)對象晉升的時候是到Survivor分區仍是到老年代分區。 年輕代收集首先先將晉升對象尺寸總和、對象年齡信息維護到年齡表中,再根據年齡表、Survivor尺寸、Survivor填充容量-XX:TargetSurvivorRatio(默認50%)、最大任期閾值-XX:MaxTenuringThreshold(默認15),計算出一個恰當的任期閾值,凡是超過任期閾值的對象都會被晉升到老年代。

混合收集集合 CSet of Mixed Collection

年輕代收集不斷活動後,老年代的空間也會被逐漸填充。當老年代佔用空間超過整堆比IHOP閾值-XX:InitiatingHeapOccupancyPercent(默認45%)時,G1就會啓動一次混合垃圾收集週期。

爲了知足暫停目標,G1可能不能一口氣將全部的候選分區收集掉,所以G1可能會產生連續屢次的混合收集與應用線程交替執行,每次STW的混合收集與年輕代收集過程相相似。

  • 爲了肯定包含到年輕代收集集合CSet的老年代分區,JVM經過參數混合週期的最大總次數-XX:G1MixedGCCountTarget(默認8)、堆廢物百分比-XX:G1HeapWastePercent(默認5%)。

經過候選老年代分區總數與混合週期最大總次數,肯定每次包含到CSet的最小分區數量;

根據堆廢物百分比,當收集達到參數時,再也不啓動新的混合收集。而每次添加到CSet的分區,則經過計算獲得的GC效率進行安排。

G1的活動週期

G1的垃圾回收包括瞭如下幾種:

  • Concurrent Marking Cycle (併發收集) 相似 CMS的併發收集過程。

  • Young Collection (YGC,年輕代收集,STW

  • Mixed Collection Cycle (混合收集,STW

  • Full GC(FGC, STWJDK10之前FGC是串行回收,JDK10+能夠是並行回收。

併發標記週期 Concurrent Marking Cycle

併發標記週期是G1中很是重要的階段,這個階段將會爲混合收集週期識別垃圾最多的老年代分區。

整個週期完成根標記、識別全部(可能)存活對象,並計算每一個分區的活躍度,從而肯定GC效率等級。

當達到IHOP閾值-XX:InitiatingHeapOccupancyPercent(老年代佔整堆比,默認45%)時,便會觸發併發標記週期。

整個併發標記週期將由初始標記(Initial Mark)、根分區掃描(Root Region Scanning)、併發標記(Concurrent Marking)、從新標記(Remark)、清除(Cleanup)幾個階段組成。

其中,初始標記(隨年輕代收集一塊兒活動)、從新標記、清除是STW的,而併發標記若是來不及標記存活對象,則可能在併發標記過程當中,G1又觸發了幾回年輕代收集(YGC)。

Initial Marking (初始標記, STW)

它標記了從GC Root開始直接可達的對象。

事實上,當達到IHOP閾值時,G1並不會當即發起併發標記週期,而是等待下一次年輕代收集,利用年輕代收集的STW時間段,完成初始標記,這種方式稱爲借道(Piggybacking)。

Root region scanning (根分區掃描)

在初始標記暫停結束後,年輕代收集也完成的對象複製到Survivor的工做,應用線程開始活躍起來。此時爲了保證標記算法的正確性,全部新複製到Survivor分區的對象,都須要被掃描並標記成根,這個過程稱爲根分區掃描(Root Region Scanning),同時掃描的Suvivor分區也被稱爲根分區(Root Region)。

Concurrent Marking(併發標記)

這個階段從GC Root開始對heap中的對象標記,標記線程與應用程序線程並行執行,而且收集各個Region的存活對象信息。 和應用線程併發執行,併發標記線程在併發標記階段啓動,由參數-XX:ConcGCThreads(默認GC線程數的1/4,即-XX:ParallelGCThreads/4)控制啓動數量, 每一個線程每次只掃描一個分區Region,從而標記出存活對象圖。

全部的標記任務必須在堆滿前就完成掃描,若是併發標記耗時很長,那麼有可能在併發標記過程當中,又經歷了幾回年輕代收集。 若是堆滿前沒有完成標記任務,則會觸發擔保機制,經歷一次長時間的串行Full GC。

Remark ( 從新標記,STW)

標記那些在併發標記階段發生變化的對象,將被回收。 這個階段也是並行執行的,經過參數-XX:ParallelGCThread可設置GC暫停時可用的GC線程數。

Cleanup (清理,STW)

清除階段主要執行如下操做:

  • RSet梳理,啓發式算法會根據活躍度和RSet尺寸對分區定義不一樣等級,同時RSet數理也有助於發現無用的引用。參數-XX:+PrintAdaptiveSizePolicy能夠開啓打印啓發式算法決策細節;
  • 整理堆分區,爲混合收集週期識別回收收益高(基於釋放空間和暫停目標)的老年代分區集合;
  • 識別全部空閒分區,即發現無存活對象的分區。該分區可在清除階段直接回收,無需等待下次收集週期。

年輕代收集 Young Collection /混合收集週期 Mixed Collection Cycle

當應用運行開始時,堆內存可用空間還比較大,只會在年輕代滿時,觸發年輕代收集;

隨着老年代內存增加,當到達IHOP閾值-XX:InitiatingHeapOccupancyPercent(老年代佔整堆比,默認45%)時,G1開始着手準備收集老年代空間。

首先經歷併發標記週期 Concurrent Marking Cycle,識別出高收益的老年代分區,前文已述。

但隨後G1並不會立刻開始一次混合收集,而是讓應用線程先運行一段時間,等待觸發一次年輕代收集。

在此次STW中,G1將保準整理混合收集週期。接着再次讓應用線程運行,當接下來的幾回年輕代收集時,將會有老年代分區加入到CSet中,

即觸發混合收集,這些連續屢次的混合收集稱爲混合收集週期(Mixed Collection Cycle)。

年輕代收集 Young Collection,YGC

每次收集過程當中,既有並行執行的活動,也有串行執行的活動,但均可以是多線程的。

在並行執行的任務中,若是某個任務太重,會致使其餘線程在等待某項任務的處理,須要對這些地方進行優化。

如下部分部分能夠結合日誌查看

  • 並行活動

    • 外部根分區掃描 Ext Root Scanning: 此活動對堆外的根(JVM系統目錄、VM數據結構、JNI線程句柄、硬件寄存器、全局變量、線程對棧根)進行掃描,發現那些沒有加入到暫停收集集合CSet中的對象。若是系統目錄(單根)擁有大量加載的類,最終可能其餘並行活動結束後,該活動依然沒有結束而帶來的等待時間。

    • 更新已記憶集合 Update RS: 併發優化線程會對髒卡片的分區進行掃描更新日誌緩衝區來更新RSet,但只會處理全局緩衝列表。做爲補充,全部被記錄可是尚未被優化線程處理的剩餘緩衝區,會在該階段處理,變成已處理緩衝區(Processed Buffers)。爲了限制花在更新RSet的時間,能夠設置暫停佔用百分比-XX:G1RSetUpdatingPauseTimePercent(默認10%,即-XX:MaxGCPauseMills/10)。值得注意的是,若是更新日誌緩衝區更新的任務不下降,單純地減小RSet的更新時間,會致使暫停中被處理的緩衝區減小,將日誌緩衝區更新工做推到併發優化線程上,從而增長對Java應用線程資源的爭奪。

    • RSet掃描 Scan RS: 在收集當前CSet以前,考慮到分區外的引用,必須掃描CSet分區的RSet。若是RSet發生粗化,則會增長RSet的掃描時間。 開啓診斷模式-XX:UnlockDiagnosticVMOptions後, 經過參數-XX:+G1SummarizeRSetStats能夠肯定併發優化線程是否可以及時處理更新日誌緩衝區,並提供更多的信息,來幫助爲RSet粗化總數提供窗口。 參數-XX:G1SummarizeRSetStatsPeriod=n可設置RSet的統計週期,即經歷多少此GC後進行一次統計

    • 代碼根掃描 Code Root Scanning:對代碼根集合進行掃描,掃描JVM編譯後代碼Native Method的引用信息(nmethod掃描),進行RSet掃描。事實上,只有CSet分區中的RSet有強代碼根時,纔會作nmethod掃描,查找對CSet的引用。

    • 轉移和回收 Object Copy: 經過選定的CSet以及CSet分區完整的引用集,將執行暫停時間的主要部分:CSet分區存活對象的轉移、CSet分區空間的回收。經過工做竊取機制來負載均衡地選定複製對象的線程,而且複製和掃描對象被轉移的存活對象將拷貝到每一個GC線程分配緩衝區GCLAB。G1會經過計算,預測分區複製所花費的時間,從而調全年輕代的尺寸。

    • 終止 Termination: 完成上述任務後,若是任務隊列已空,則工做線程會發起終止要求。若是還有其餘線程繼續工做,空閒的線程會經過工做竊取機制嘗試幫助其餘線程處理。而單獨執行根分區掃描的線程,若是任務太重,最終會晚於終止。

    • GC外部的並行活動 GC Worker Other: 該部分並不是GC的活動,而是JVM的活動致使佔用了GC暫停時間(例如JNI編譯)。

  • 串行活動

    • 代碼根更新 Code Root Fixup:根據轉移對象更新代碼根。

    • 代碼根清理 Code Root Purge:清理代碼根集合表。

    • 清除全局卡片標記 Clear CT:在任意收集週期會掃描CSet與RSet記錄的PRT,掃描時會在全局卡片表中進行標記,防止重複掃描。在收集週期的最後將會清除全局卡片表中的已掃描標誌。

    • 選擇下次收集集合 Choose CSet:該部分主要用於併發標記週期後的年輕代收集、以及混合收集中,在這些收集過程當中,因爲有老年代候選分區的加入,每每須要對下次收集的範圍作出界定;但單純的年輕代收集中,全部收集的分區都會被收集,不存在選擇。

    • 引用處理 Ref Proc:主要針對軟引用、弱引用、虛引用、final引用、JNI引用。當Ref Proc佔用時間過多時,可選擇使用參數-XX:ParallelRefProcEnabled激活多線程引用處理。G1但願應用能當心使用軟引用,由於軟引用會一直佔據內存空間直到空間耗盡時被Full GC回收掉;即便未發生Full GC,軟引用對內存的佔用,也會致使GC次數的增長。

    • 引用排隊 Ref Enq:此項活動可能會致使RSet的更新,此時會經過記錄日誌,將關聯的卡片標記爲髒卡片。

    • 卡片從新髒化 Redirty Cards:從新髒化卡片。

    • 回收空閒巨型分區 Humongous Reclaim:G1作了一個優化:經過查看全部根對象以及年輕代分區的RSet,若是肯定RSet中巨型對象沒有任何引用,則說明G1發現了一個不可達的巨型對象,該對象分區會被回收。

    • 釋放分區 Free CSet:回收CSet分區的全部空間,並加入到空閒分區中。

    • 其餘活動 Other:GC中可能還會經歷其餘耗時很小的活動,如修復JNI句柄等。

併發標記週期後的年輕代收集 Young Collection Following Concurrent Marking Cycle

當G1發起併發標記週期以後,並不會立刻開始混合收集。 G1會先等待下一次年輕代收集,而後在該收集階段中,肯定下次混合收集的CSet(Choose CSet)。

混合收集週期 Mixed Collection Cycle, Mixed GC

單次的混合收集與年輕代收集並沒有二致。

根據暫停目標,老年代的分區可能不能一次暫停收集中被處理完,G1會發起連續屢次的混合收集,稱爲混合收集週期(Mixed Collection Cycle)。

G1會計算每次加入到CSet中的分區數量、混合收集進行次數,而且在上次的年輕代收集、以及接下來的混合收集中,G1會肯定下次加入CSet的分區集(Choose CSet),而且肯定是否結束混合收集週期。

轉移失敗的擔保機制 Full GC

轉移失敗(Evacuation Failure)是指當G1沒法在堆空間中申請新的分區時,G1便會觸發擔保機制,執行一次STW式的、單線程(JDK10支持多線程)的Full GC。

Full GC會對整堆作標記清除和壓縮,最後將只包含純粹的存活對象。參數-XX:G1ReservePercent(默認10%)能夠保留空間,來應對晉升模式下的異常狀況,最大佔用整堆50%,更大也無心義。

G1在如下場景中會觸發Full GC,同時會在日誌中記錄to-space exhausted以及Evacuation Failure

  • 從年輕代分區拷貝存活對象時,沒法找到可用的空閒分區
  • 從老年代分區轉移存活對象時,沒法找到可用的空閒分區
  • 分配巨型對象Humongous Object 時在老年代沒法找到足夠的連續分區

因爲G1的應用場合每每堆內存都比較大,因此Full GC的收集代價很是昂貴,應該避免Full GC的發生。

問題

  • 何時觸發concurrent marking ?
# 啓動併發週期 Concurrent Marking Cycle (以及後續的混合週期 MixedGC)時的堆內存佔用百分比. G1用它來觸發併發GC週期,基於整個堆的使用率,而不僅是某一代內存的使用比例。默認45%
# 當堆存活對象佔用堆的45%,就會啓動G1 中併發標記週期 Concurrent Marking Cycle
-XX:InitiatingHeapOccupancyPercent
複製代碼
  • 何時發生Mixed GC? concurrent marking 主要是爲Mixed GC提供標記服務的,並非一次GC過程的一個必須環節。

    由一些參數控制,另外也控制着哪些老年代Region會被選入CSet(收集集合)。

# 一次 concurrent marking以後,最多執行Mixed GC的次數(默認8)
-XX:G1MixedGCCountTarget
# 堆廢物百分比(默認5%),在每次YGC以後和再次發生Mixed GC以前,會檢查垃圾佔比是否達到此參數,只有達到了,下次纔會發生Mixed GC。
-XX:G1HeapWastePercent
# old generation region中的存活對象的佔比,只有在此參數之下,纔會被選入CSet。
-XX:G1MixedGCLiveThresholdPercent
# 一次Mixed GC中能被選入CSet的最多old generation region數量。
-XX:G1OldCSetRegionThresholdPercent
複製代碼

GC日誌詳解

併發標記週期 Concurrent Marking Cycle
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0094252 secs]
# 根分區掃描,可能會被 YGC 打斷,那麼結束就是如:[GC pause (G1 Evacuation Pause) (young)[GC concurrent-root-region-scan-end, 0.0007157 secs]
[GC concurrent-mark-start]
[GC concurrent-mark-end, 0.0203881 secs]
# 併發標記階段
[GC remark [Finalize Marking, 0.0007822 secs] [GC ref-proc, 0.0005279 secs] [Unloading, 0.0013783 secs], 0.0036513 secs]
# 從新標記,STW
 [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC cleanup 13985K->13985K(20480K), 0.0034675 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
# 清除
複製代碼
年輕代收集 YGC
[GC pause (G1 Evacuation Pause) (young), 0.0022483 secs]
# young -> 年輕代 Evacuation-> 複製存活對象 
   [Parallel Time: 1.0 ms, GC Workers: 10] # 併發執行的GC線程數,如下階段是併發執行的
      [GC Worker Start (ms): Min: 109.0, Avg: 109.1, Max: 109.1, Diff: 0.2] 
      [Ext Root Scanning (ms): Min: 0.1, Avg: 0.2, Max: 0.3, Diff: 0.2, Sum: 2.3] # 外部根分區掃描
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] # 更新已記憶集合 Update RSet,檢測從年輕代指向老年代的對象
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0] 
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]# RSet掃描
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1] # 代碼根掃描
      [Object Copy (ms): Min: 0.3, Avg: 0.3, Max: 0.4, Diff: 0.1, Sum: 3.5] # 轉移和回收,拷貝存活的對象到survivor/old區域
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] # 完成上述任務後,若是任務隊列已空,則工做線程會發起終止要求。
         [Termination Attempts: Min: 1, Avg: 5.8, Max: 9, Diff: 8, Sum: 58]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1] # GC外部的並行活動,該部分並不是GC的活動,而是JVM的活動致使佔用了GC暫停時間(例如JNI編譯)。
      [GC Worker Total (ms): Min: 0.5, Avg: 0.6, Max: 0.7, Diff: 0.2, Sum: 5.9]
      [GC Worker End (ms): Min: 109.7, Avg: 109.7, Max: 109.7, Diff: 0.0]
   [Code Root Fixup: 0.0 ms] # 串行任務,根據轉移對象更新代碼根
   [Code Root Purge: 0.0 ms] #串行任務, 代碼根清理
   [Clear CT: 0.5 ms] #串行任務,清除全局卡片 Card Table 標記
   [Other: 0.8 ms]
      [Choose CSet: 0.0 ms] # 選擇下次收集集合  CSet
      [Ref Proc: 0.4 ms] # 引用處理 Ref Proc,處理軟引用、弱引用、虛引用、final引用、JNI引用
      [Ref Enq: 0.0 ms] # 引用排隊 Ref Enq
      [Redirty Cards: 0.3 ms] # 卡片從新髒化 Redirty Cards:從新髒化卡片
      [Humongous Register: 0.0 ms] 
      [Humongous Reclaim: 0.0 ms] # 回收空閒巨型分區 Humongous Reclaim,經過查看全部根對象以及年輕代分區的RSet,若是肯定RSet中巨型對象沒有任何引用,該對象分區會被回收。
      [Free CSet: 0.0 ms]  # 釋放分區 Free CSet
   [Eden: 12288.0K(12288.0K)->0.0B(11264.0K) Survivors: 0.0B->1024.0K Heap: 12288.0K(20480.0K)->832.0K(20480.0K)]
 [Times: user=0.01 sys=0.00, real=0.00 secs] 
複製代碼
# 從年輕代分區拷貝存活對象時,沒法找到可用的空閒分區
# 從老年代分區轉移存活對象時,沒法找到可用的空閒分區 這兩種狀況之一致使的 YGC
[GC pause (G1 Evacuation Pause) (young) (to-space exhausted), 0.0916534 secs]
複製代碼
# 併發標記週期 Concurrent Marking Cycle 中的 根分區掃描階段,被 YGC中斷
[GC pause (G1 Evacuation Pause) (young)[GC concurrent-root-region-scan-end, 0.0007157 secs]
複製代碼
混合收集週期 Mixed Collection Cycle, Mixed GC
# 併發標記週期 Concurrent Marking Cycle 的開始
[GC pause (G1 Evacuation Pause) (young) (initial-mark) , 0.0443460 secs]
複製代碼
Full GC
[Full GC (Allocation Failure) 20480K->9656K(20480K), 0.0189481 secs]
   [Eden: 0.0B(1024.0K)->0.0B(5120.0K) Survivors: 0.0B->0.0B Heap: 20480.0K(20480.0K)->9656.8K(20480.0K)], [Metaspace: 4960K->4954K(1056768K)]
 [Times: user=0.03 sys=0.00, real=0.02 secs] 
複製代碼

參考資料

by Sven Augustus my.oschina.net/langxSpirit

本文由博客羣發一文多發等運營工具平臺 OpenWrite 發佈

相關文章
相關標籤/搜索