G1
垃圾收集器的设计原则是“首先收集尽量多的垃圾(Garbage First)”,目标是为了尽可能缩短处理超大堆(超过4GB)产生的停顿。html
所以,G1
并不会等内存耗尽(好比Serial
串行收集器、Parallel
并行收集器 )者快耗尽(CMS
)的时候才开始垃圾回收,而是在内部采用了启发式算法,在老年代中找出具备高收集收益的分区(Region
)进行收集。java
同时 G1
能够根据用户设置的STW
(Stop-The-World)停顿时间目标(响应时间优先)自动调全年轻代和总堆的大小,停顿时间越短年轻代空间就可能越小,总堆空间越大。web
G1
相对于CMS
一个比较明显的优点是,内存碎片的产生率大大下降。算法
G1
在 JDK7u4以上均可以使用,在JDK9开始,G1
为默认的垃圾收集器,以替代CMS
。shell
算法:三色标记 + SATBbash
STW
(Stop-The-World)停顿时间。Region
)。Remembered Set
来避免全堆扫描。传统的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空间;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 Object
在 YGC
阶段, Global Concurrent Marking
阶段的 Cleanup
和 FGC
阶段 回收。因为没法享受
LAB
带来的优化,而且肯定一片连续的内存空间须要扫描整堆Heap
,所以肯定巨型对象开始位置的成本很是高,若是能够,应用程序应避免生成巨型对象。
Humongous Object
以前先检查是否超过 initiating heap occupancy percent (由参数-XX:InitiatingHeapOccupancyPercent
控制) 和 the marking threshold。 若是超过的话,就启动并发收集周期Concurrent Marking Cycle
,为的是提前回收,防止 Evacuation Failure
和 Full GC
。RSet
(Remember 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
扫描才能找出全部引用,所以扫描速度也是最慢的。
CSet
(Collection 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
的混合收集与年轻代收集过程相相似。
-XX:G1MixedGCCountTarget
(默认8)、堆废物百分比-XX:G1HeapWastePercent
(默认5%)。经过候选老年代分区总数与混合周期最大总次数,肯定每次包含到CSet
的最小分区数量;
根据堆废物百分比,当收集达到参数时,再也不启动新的混合收集。而每次添加到CSet
的分区,则经过计算获得的GC效率进行安排。
G1的垃圾回收包括了如下几种:
Concurrent Marking Cycle (并发收集) 相似 CMS
的并发收集过程。
Young Collection (YGC,年轻代收集,STW
)
Mixed Collection Cycle (混合收集,STW
)
Full GC(FGC, STW
) JDK10之前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
能够开启打印启发式算法决策细节;当应用运行开始时,堆内存可用空间还比较大,只会在年轻代满时,触发年轻代收集;
随着老年代内存增加,当到达IHOP阈值-XX:InitiatingHeapOccupancyPercent
(老年代占整堆比,默认45%)时,G1开始着手准备收集老年代空间。
首先经历并发标记周期 Concurrent Marking Cycle
,识别出高收益的老年代分区,前文已述。
但随后G1并不会立刻开始一次混合收集,而是让应用线程先运行一段时间,等待触发一次年轻代收集。
在此次STW中,G1将保准整理混合收集周期。接着再次让应用线程运行,当接下来的几回年轻代收集时,将会有老年代分区加入到CSet中,
即触发混合收集,这些连续屡次的混合收集称为混合收集周期(Mixed Collection Cycle
)。
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句柄等。
当G1发起并发标记周期以后,并不会立刻开始混合收集。 G1会先等待下一次年轻代收集,而后在该收集阶段中,肯定下次混合收集的CSet(Choose CSet)。
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 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-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]
# 清除
复制代码
[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]
复制代码
# 并发标记周期 Concurrent Marking Cycle 的开始
[GC pause (G1 Evacuation Pause) (young) (initial-mark) , 0.0443460 secs]
复制代码
[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 发布