向前迈进!走入GC世界:G1 GC原理深入解析

news2024/11/26 22:27:04

第零章:名词解释

mutator:应用线程

STW:Stop-The-World,指除了GC线程,其它所有线程全部暂停的一段时间

并发:指代GC线程与mutator在同一时刻执行任务

并行:指代多个GC线程在同一时刻执行任务

Young GC:新生代回收

Mixed GC:混合回收

Full GC:整堆回收

第一章:G1基本概念

这里介绍的主要是一些老生常谈的内容,比较熟悉的同学可以直接跳过本部分内容

G1的目标

G1作为一个增量垃圾回收器,致力于保证高吞吐量与软实时性的最佳平衡,其应用场景最好需要包含以下特性(满足这些特性的话,则可能更适合G1出马,否则可能其他GC更合适):

  • 堆内存大小超过10G,且存活对象占用比例超过50%
  • 对象分配和晋升速率可能随时间有显著变化
  • 堆中存在大量碎片
  • 预测的最大停顿时间不超过几百毫秒

对于其它垃圾回收器来说,由于整堆回收的特性和缺乏启发式调整的机制,导致其无法很好的应付上述场景,而G1由于开创性的停顿预测模型与独特的堆结构,则恰恰相反。

增量GC:通过慢慢GC来缩短mutator最大暂停时间的一种手段

G1的堆结构

 G1 GC 堆分布图

G1中,将堆内存划分为了大小相等的内存块,称之为Heap Region,Heap Region是内存分配和内存回收的最小单位,由于全称过长,后文中可能使用分区、区域或HR代指Heap Region,望知悉。

图中红色区域指代的是新生代(young generation),蓝色区域指代的是老年代(old generation),标注为S的红色区域的为Suvivor Region,标注为H的蓝色区域为Humoungous Region。

从上图中可以看到,在G1收集器中,对象占用的内存和代际的分布都不是连续的,而且对于灰色区域来说,它随时可以为了实现软实时性,成为任何确定的代际区域,这是G1和其他收集器在堆内存结构上的最大差别,也是为什么G1更适合处理「堆中存在大量碎片」场景的原因。

新生代&老年代:通常垃圾收集器会根据对象的特性来选择不同的算法进行垃圾回收,对象会依据特性存储在不同的内存区域中,使用不同的回收算法。新生代&老年代便是依据对象生命周期所划分的内存区域。

停顿预测模型

在G1 GC中,用户通过-XX:MaxGCPauseMills 来设定期望最大停顿时间,而具体则是由G1 GC中的停顿预测模型实现。

卡表

JVM将堆内存划分为了2次幂大小的卡页(Card Page),使用卡表来记录其内存状态。默认情况下,卡页的大小为512B。

卡表(Card Table)是由1B组成的数组,卡表里的元素称为卡片(Card),每个卡片对应堆内存中的一个卡页,卡片数组位置为堆内存地址除卡页大小(向下取整)。

 卡表与卡页映射关系图

堆中的对象所对应的卡片在卡表中的索引值可以通过以下公式快速计算出来。

(对象的地址-堆的头部地址)/512

卡表是一个全局表,其核心是利用了分桶思想,牺牲了一定的索引效率,不过使得JVM仅使用少量内存上即能快速描述内存状态。

记忆集(RSet)

记忆集与卡表密切相关,上一节中介绍了卡表的结构和职责,但是仍不知其具体应用场景有哪些

,接下来我便来介绍其最为重要的一个应用场景:记忆集。

记忆集英文全称为RemerberSet,简称RSet,是一种抽象概念,其核心思想是借由卡表,记录对象在不同代际间的引用关系,加速垃圾回收的速度。

JVM会通过可达性分析算法标记存活对象来帮助进行垃圾回收,不过在分代GC中,新生代和老年代处于不同的回收阶段,如果我仅仅只需要需要回收新生代,却标记了老年代的对象,那么这无疑是不必要的,所以JVM设计了RSet这样的玩意来避免这种现象,使其即便不扫描全部对象,也可以查到待回收对象所在分区被其它分区引用的情况。

记忆集的结构及使用示例

假设有两个分区(Heap Region),其区域内对象的引用关系如下图所示:

每个HR中都会额外开辟一块存储空间,用于存储记忆集,记忆集的结构为一个Hash表,Key为引用本分区的其它分区的地址,Value是卡片(Card)在卡表的索引值,即分区中的哪些卡页引用了本分区。

拿上图两个分区的引用关系举例,对象b引用了对象a,则在HR A中的记忆集,会存储对象b所在卡页对本分区的引用。在这个图中,对象b所在区域为HR B,所在卡页对应卡表索引2048的位置,则HR A的记忆集中会新增一个「B-2048」的引用关系

 记忆集结构图

记忆集如何筛选记录引用关系

上边介绍了记忆集的结构及其如何记录引用关系的示例,但是堆对象引用那么多,如果全部一一记录的话,我们的内存就爆炸了,所以我们需要明确哪些引用关系我们需要记录,哪些我们不需要记录。

在G1中提供了3种收集算法。新生代回收、混合回收和FullGC。新生代回收总是收集所有新生代分区,混合回收会收集所有的新生代分区以及部分老生代分区,而FullGC则是对所有的分区处理。简单了解这些后,我们对所有引用关系分类分析:

  • 分区内部间的引用:无需记录引用关系,前文所说,Heap Region是内存分配和回收的最小单位,要么都回收,要么都不回收
  • 新生代分区到新生代分区的引用:无需记录引用关系,无论哪种类型的回收,新生代都会全量回收
  • 新生代分区到老年代分区的引用:无需记录引用关系,
  • 老年代分区到新生代分区的引用:需要记录引用关系,新生代回收时,有两种根,一种是栈空间/全局变量的引用,另一种便是老年代到新生代的引用
  • 老年代分区到老年代分区的引用:需要记录引用关系,混合回收时可能只回收部分Region,需要记录引用关系,快速找到活跃对象
这里说的引用关系,指的是分区间的引用关系,不要认为不记录分区间的引用关系,那么对象间也就没有引用关系了

记忆集记录的引用关系具体什么时候会使用

参考「第三章:垃圾回收过程」的「转移(垃圾回收)」小节

记忆集写屏障

记忆集其作用是HR间的引用关系,为保证其正确性,那么当引用关系变化时,我们需要及时更新记忆集,而记忆集写屏障则能帮我们完成这个工作。其工作的伪代码如下所示:

def evacuation_write_barrier(obj,field,newobj):
	check=obj^newobj # 异或
	check=check>>LOG_OF_HEAP_REGION_SIZE # 判断高位
	if newobj==Null:
		check=0
	if check==0:
		return
    
	if not is_dirty_card(obj):
		to_dirty(obj) # 标记为dirty card
		enqueue($current_thread.rs_log,obj)
    
	*field=newobj

obj为引用对象的地址,newobj为被引用对象的地址,field为obj的成员变量,上边这段代码的背景是obj的filed字段重新修改引用为newObj,所以obj新增了一个对其它分区的引用关系,需要通过写屏障记录。

解释一下这段代码干了什么事情,2~7行用于过滤同个HR间的引用,通过两个对象间的地址的异或(XOR),最终使异或结果左移LOG_OF_HEAP_REGION_SIZE,从而通过判断高位是否一致,来判断被引用对象和引用对象是否在同一个分区,如果是一个分区则不需要记录引用关系的变化了。

LOG_OF_HEAP_REGION_SIZE:Heap Region大小以2为底的对数

在9~11行,用来将对象对应卡片,加入dirty_card_queue,简称DCQ,DCQ由线程持有,当DCQ慢了之后,会放入一个全局的DCQS队列,最终会由Refine线程遍历其中的DCQ,更新Rset的索引关系,其过程如下所示

Refine线程:专门用于处理RSet更新的线程,Refine线程会和Mutator线程并发执行,由于G1在真正执行转移(垃圾回收)阶段时,会强制更新一次Rset,所以Refine线程的主要作用是提前处理RSet的更新,避免转移(垃圾回收)时停顿时间过长

第二章:对象分配过程

快速分配

快速分配指的是基于线程本地分配缓冲区(Thread Local Allocation Buffer)的分配。

通常来说,JVM堆是所有线程的共享区域,因此,从JVM堆空间分配对象时,必须锁定整个堆,以免被其它线程中断影响,而为了避免资源竞争降低对象分配效率,TLAB通过给每个线程分配一个缓冲区,来使其进行快速无锁分配。

 对象分配流程图

当一个对象快速分配失败时(通常是TLAB剩余空间不足以分配该对象),线程会视TLAB使用情况决定是否要将这个TLAB归还到堆空间中去,并再申请一个TLAB,如果判断需要这么做时,则会在TLAB分配成功后,再次尝试快速分配,否则则进入慢速分配。

那么什么情况,JVM会判断该线程需要再申请一个TLAB呢?实际上虚拟机会维护一个refill_waste的值,当对象在TLAB分配对象失败时,如果对象大小大于refill_waste,则让其直接进行在堆分配,如果对象大小小于refill_waste,则为其重新分配一个TLAB,将对象分配在新TLAB上。refill_waste的值可用通过TLABRefillWasteFraction,默认值是64,也就是说默认refill_waste=TLABSize/64

慢速分配

快速分配失败则进入慢速分配

大对象分配

大对象分配也是慢速分配的一种,步骤如下

  • 尝试垃圾回收,同时启动并发标记。
  • 尝试开始分配对象,对于大对象分为两类,一类是大于HeapRegionSize的一半,但是小于HeapRegionSize,即一个完整的堆分区可以保存,则直接从空闲列表直接拿一个堆分区,或者分配一个新的堆分区。另一类则是不仅大于HeapRegionSize的一半,还大于HeapRegionSize,即连续对象,需要多个堆分区,思路同上,但是处理的时候需要加锁。
  • 如果失败再次尝试垃圾回收,之后再分配。
  • 最终成功分配或者失败达到一定次数,则分配失败

第三章:垃圾回收过程

Garbage Collection Cycle

前文我们说过G1的GC有三种:新生代GC、混合GC、Full GC。不过按阶段来的话,G1的回收只有两个阶段,Young-OnlySpace Relcaimation阶段。

在Young Only阶段,G1只会回收新生代内存,即新生代回收,在Space Reclamation阶段,G1除了会全量回收新生代内存,还会回收老年代区域,即混合回收。Full GC是一种特殊的兜底回收逻辑,此处不考虑进来。

所以G1的垃圾回收其实不是我们所想的Young GC和Mixed GC穿插进行,而是Young GC 持续一段时间,Mixed GC 再持续一段时间。

Garbage Collection Cycle概览图

那么G1如何判断什么时候进入Space Reclamation阶段呢?参照上图,当老年代堆内存占比超过一定阈值时,G1会开始并发标记,当并发标记的最后一个阶段Clean Up阶段完成后,G1则会进入Space Reclamation阶段,进行Mixed GC。

并发标记

并发标记的时机是在YGC后,只有达到InitiatingHeapOccupancyPercent阈值后,才会触发并发标记。InitiatingHeapOccupancyPercent默认值是45。

并发标记阶段分为4个子阶段

1、初始标记阶段(Initial Mark)

负责标记所有直接可达的根对象(栈对象、全局对象、JNI对象等),初始标记伴随一次YGC,因此初始标记需要将Mutator线程暂停,也就是需要一个STW的时间。

2、并发标记子阶段(Concurrent Start)

根据新生代的Survivor分区以及老生代的RSet开始并发标记存活对象。

3、再标记子阶段(Remark)

再标记(Remark)是最后一个标记阶段。由于并发标记子阶段时,Mutator线程仍在不断修改对象引用关系,因此在该阶段中,G1需要一个STW,找出所有未被访问的存活对象。

4、清理子阶段(Clean Mark)

再标记阶段之后进入清理子阶段,也是需要STW的。清理子阶段主要执行以下操作:

  • 统计存活对象,统计的结果将会用来排序分区,以用于下一次的CSet的选择;根据SATB算法,需要把新分配的对象,即不在本次并发标记范围内的新分配对象,都视为活跃对象。
  • 交换标记位图,为下次并发标记准备。
  • 重置RSet,此时老生代分区已经标记完成,如果标记后的分区没有引用对象,这说明引用已经改变,这个时候可以删除原来的RSet里面的引用关系。
  • 把空闲分区放到空闲分区列表中;这里的空闲指的是全都是垃圾对象的分区;如果分区还有任何分区活跃对象都不会释放,真正释放是在混合GC中。

 并发标记流程图

并发标记阶段完成后,即能够获得所有候选的回收集,G1会根据其回收价值进行排序,在MixedGC时,在满足期望最大停顿时间的前提下,筛选最具有回收价值的回收集

转移(垃圾回收)

转移是Young GC和Mixed GC都会执行的过程,是我们常说的垃圾回收。

在并发标记完成后,G1能筛选出所有候选的回收集,并根据用户定义的期望最大停顿时间,筛选本次转移真正的回收集(CSet),标记回收集中的存活对象,将这些对象转移,完成垃圾回收。

Young GC 的回收只包含全量新生代区域,意味着Young GC 不需要耗费时间来筛选回收集,整个新时代都是回收集,Mixed GC 由于除了回收全量新生代区域,还会回收部分老年代区域,所以需要耗费时间来筛选回收集

既然需要标记存活对象,那么就需要从根引用进行可达性分析,来进行标记。

在转移过程中,除了会使用栈空间、全局变量等根,还会将CSet中的记忆集作为根,进行扫描。

 转移(垃圾回收)流程图

如果此刻G1处于Space Reclamation阶段,则一定不需要进行并发标记,因为进入Space Reclamation阶段,意味着已完成并发标记,Space Reclamation阶段在回收到一定阈值才会停下,再次进入Young-Only阶段

转移其核心逻辑此处使用伪代码进行表示(以下伪代码摘抄自《深入Java虚拟机:JVM G1GC的算法与实现》,本人主要负责解释说明):

def evacuate_roots():
	for r in $roots: # 遍历root集合,
		if is_into_collection_set(*r):
			*r=evacuate_obj(r) # 转移根对象到空闲区域
	force_update_rs() # 强制更新RSet
    for regionin $collection_set: # 遍历回收集
    	for card in region.rs_cards: # 遍历Region记忆集中的卡页
    		scan_card(card)
    
    def scan_card(card):
    	for obj in objects_in_card(card): # 遍历卡页中的对象
    		if is_marked(obj): # 如果该对象已经标记了,就是说该对象是存活的
    			for child in children(obj): # 遍历其引用
    				if is_into_collection_set(*child): # 如果引用的对象在回收集中
    					*child=evacuate_obj(child) #转移对象到空闲区域
    
    def evacuate_obj(ref):
    	from=*ref 
    	if not is_marked(from): # 如果待转移对象非存活对象,返回
    		return from
    	if from.forwarded: # 如果待转移对象已经转移,重定向地址为转移后地址,并返回转移后地址
    		add_reference(ref,from.forwarded)
    	  return from.forwarding
    	to=allocate($free_region,from.size) # 分配内存空间,用于转移待转移对象
    	copy_data(new,from,from.size) # 转移数据
    	
        from.forwarding=to # 重定向引用
      	from.forwarded=True # 标记对象已转移
      
      	for child in children(to): # 扫描待转移对象的引用关系,加入到队列中,待后续扫描标记
        	if is_into_collection_set(*child):
      			enqueue($evacuate_queue,child)
      	  else:
      			add_reference(child,*child)
      	
        add_reference(ref,to)
        return to
        

第四章:GC日志解读

这里以截取的一段GC日志为例,帮助各位理解GC日志

# 触发并发标记,原因:大对象分配,老年代占比超过IHOP阈值
# occupancy指老年代占有内存大小,allocation request指本次对象分配所需申请内存
# threshold指阈值
[gc,ergo,ihop      ] Request concurrent cycle initiation (occupancy higher than threshold) occupancy: 18790481920B allocation request: 16777248B threshold: 18790481920B (50.00) source: concurrent humongous allocation
[safepoint         ] Application time: 0.1052313 seconds
# 看名字也能看得出来,collect for allocation
[safepoint         ] Entering safepoint region: G1CollectForAllocation
[gc,ergo           ] Request concurrent cycle initiation (requested by GC cause). GC cause: G1 Humongous Allocation
[gc,heap           ] GC(19615) Heap before GC invocations=19615 (full 0): garbage-first heap   total 36700160K, used 29863278K [0x00007f98dd000000, 0x00007fa19d00000)
[gc,heap           ] GC(19615)   region size 16384K, 705 young (11550720K), 34 survivors (557056K)
[gc,heap           ] GC(19615)  Metaspace       used 580660K, capacity 592798K, committed 598784K, reserved 600064K
# 启动并发标记
[gc,ergo           ] GC(19615) Initiate concurrent cycle (concurrent cycle initiation requested)
# 伴随一次YoungGC
[gc,start          ] GC(19615) Pause Young (Concurrent Start) (G1 Humongous Allocation)
[gc,task           ] GC(19615) Using 24 workers of 24 for evacuation
# TLAB日志信息
# thrds:线程数 
# refills:refill的总次数 这里是91694,max表示一个周期内的最大值
# slow allocs: 发生慢速分配的次数
# waste:由三个部分组成,gc、slow、fast
# gc:发生GC时还没有使用的TLAB空间
# slow:暂时不清楚什么意思
# fast:暂时不清楚什么意思
[gc,tlab           ] GC(19615) TLAB totals: thrds: 2870  refills: 91694 max: 1434 slow allocs: 11949 max 964 waste:  1.9% gc: 154439632B max: 4864808B slow: 60164832B max: 903784B fast: 0B max: 0B
[gc,alloc,region   ] GC(3308) Mutator Allocation stats, regions: 1139, wasted size: 1789K ( 0.0%)
# 期望的survivor区占有空间,new threshold 15 表示当前对象晋升年龄为15,max threshold 15 表示最大对象晋升年龄为15
[gc,age            ] GC(3308) Desired survivor size 1249902592 bytes, new threshold 15 (max threshold 15)
# Choose CSet,由于这是一次young gc,所以Cset全是年轻代,耗时为0
[gc,ergo,cset      ] GC(3308) Finish choosing CSet. old: 0 regions, predicted old region time: 0.00ms, time remainin: 104.69
[gc,refine         ] Activated worker 0, on threshold: 666, current: 709
# GC结束阶段信息统计,通常不用关注,打出这一行日志说明本次GC已经接近尾声
[gc,task,stats     ] GC(3308) GC Termination Stats
[gc,task,stats     ] GC(3308)      elapsed  --strong roots-- -------termination------- ------waste (KiB)------
[gc,task,stats     ] GC(3308) thr     ms        ms      %        ms      %    attempts  total   alloc    undo
[gc,task,stats     ] GC(3308) --- --------- --------- ------ --------- ------ -------- ------- ------- -------
[gc,task,start     ] G1 Service Thread (Periodic GC Task) (run)
[gc,task           ] G1 Service Thread (Periodic GC Task) (run) 0.074ms (cpu: 0.035ms)
[gc,task,stats     ] GC(3308)   8    110.28     82.40  74.72      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)   5    110.36     82.41  74.67      0.02   0.02        1       0       0       0
[gc,task,stats     ] GC(3308)   2    110.42     82.45  74.67      0.02   0.02        1       0       0       0
[gc,task,stats     ] GC(3308)  18    110.37     82.75  74.98      0.02   0.02        1       0       0       0
[gc,task,stats     ] GC(3308)   6    110.45     82.41  74.62      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)  15    110.43     82.42  74.64      0.01   0.01        1       1       1       0
[gc,task,stats     ] GC(3308)   0    110.54     82.46  74.60      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)   3    110.54     82.41  74.55      0.02   0.02        1      49      49       0
[gc,task,stats     ] GC(3308)   1    110.58     82.46  74.57      0.02   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)  19    110.52     82.36  74.52      0.01   0.01        1       6       6       0
[gc,task,stats     ] GC(3308)  12    110.58     82.40  74.51      0.02   0.02        1       0       0       0
[gc,task,stats     ] GC(3308)  22    110.41     84.69  76.70      0.01   0.01        1     150     150       0
[gc,task,stats     ] GC(3308)   9    110.63     82.55  74.62      0.01   0.01        1     313     313       0
[gc,task,stats     ] GC(3308)  14    110.64     84.66  76.52      0.02   0.02        1       2       2       0
[gc,task,stats     ] GC(3308)   4    110.72     82.41  74.43      0.02   0.02        1       0       0       0
[gc,task,stats     ] GC(3308)  16    110.68     82.29  74.35      0.01   0.01        1      14      14       0
[gc,task,stats     ] GC(3308)  20    110.68     84.77  76.58      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)  10    110.78     88.72  80.09      0.02   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)   7    110.83     82.40  74.35      0.02   0.02        1       7       7       0
[gc,task,stats     ] GC(3308)  13    110.84     82.38  74.33      0.02   0.01        1       2       2       0
[gc,task,stats     ] GC(3308)  21    110.82     82.70  74.63      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)  23    110.47     82.01  74.24      0.01   0.01        1       0       0       0
[gc,task,stats     ] GC(3308)  11    110.92     82.38  74.27      0.01   0.01        1       5       5       0
[gc,task,stats     ] GC(3308)  17    110.92     85.26  76.86      0.01   0.01        1       1       1       0
# 启用Redirty任务,保证引用关系无误
[gc,ergo           ] GC(3308) Running G1 Clear Card Table Task using 24 workers for 55 units of work for 1755 regions.
[gc,ref            ] GC(3308) Skipped phase1 of Reference Processing due to unavailable references
# 释放CSet
[gc,ergo           ] GC(3308) Running G1 Free Collection Set using 24 workers for collection set length 1188
# 大对象分配信息,这里解释一下下边这一行日志:
# 312号HR分区为大对象分区,大小为16M,起始地址为0x00007f5321000000,Rset更新过1次,代码块长度为0,is marked 0表示被标记,不能被回收,且是数组类型
[gc,humongous      ] GC(3308) Live humongous region 312 object size 16777248 start 0x00007f5321000000  with remset 1 code roots 0 is marked 0 reclaim candidate 0 type array 1
[gc,humongous      ] GC(3308) Live humongous region 378 object size 8388632 start 0x00007f5363000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 410 object size 16777240 start 0x00007f5383000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 459 object size 16777240 start 0x00007f53b4000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 461 object size 16777248 start 0x00007f53b6000000  with remset 1 code roots 0 is marked 0 reclaim candidate 0 type array 1
[gc,humongous      ] GC(3308) Live humongous region 572 object size 8388632 start 0x00007f5425000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 579 object size 134217752 start 0x00007f542c000000  with remset 2 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 669 object size 16777240 start 0x00007f5486000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 677 object size 8388632 start 0x00007f548e000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 678 object size 16777240 start 0x00007f548f000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 685 object size 8388632 start 0x00007f5496000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 689 object size 16777240 start 0x00007f549a000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 691 object size 16777248 start 0x00007f549c000000  with remset 1 code roots 0 is marked 0 reclaim candidate 0 type array 1
[gc,humongous      ] GC(3308) Live humongous region 741 object size 8388632 start 0x00007f54ce000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 742 object size 16777240 start 0x00007f54cf000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Dead humongous region 747 object size 16762032 start 0x00007f54d4000000 with remset 0 code roots 0 is marked 0 reclaim candidate 1 type array 1
[gc,humongous      ] GC(3308) Live humongous region 753 object size 8388632 start 0x00007f54da000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 754 object size 16777240 start 0x00007f54db000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,humongous      ] GC(3308) Live humongous region 766 object size 12707280 start 0x00007f54e7000000  with remset 1 code roots 0 is marked 0 reclaim candidate 0 type array 1
[gc,humongous      ] GC(3308) Live humongous region 770 object size 9692992 start 0x00007f54eb000000  with remset 1 code roots 0 is marked 0 reclaim candidate 0 type array 1
[gc,humongous      ] GC(3308) Live humongous region 771 object size 8388632 start 0x00007f54ec000000  with remset 0 code roots 0 is marked 0 reclaim candidate 0 type array 0
[gc,ergo,refine    ] GC(3308) Updated Refinement Zones: green: 719, yellow: 2157, red: 3595
# 下边信息为本次GC各阶段的耗时信息
# PS:不是这个时候才执行下边这些阶段,而是执行完了,统计耗时信息
# 预回收阶段统计信息
[gc,phases         ] GC(3308)   Pre Evacuate Collection Set: 0.1ms
[gc,phases         ] GC(3308)     Prepare TLABs: 1.5ms
[gc,phases         ] GC(3308)     Choose Collection Set: 0.0ms
[gc,phases         ] GC(3308)     Humongous Register: 0.1ms
# evacuation阶段
[gc,phases         ] GC(3308)   Evacuate Collection Set: 111.1ms
// 根结点扫描的耗时信息,其中Min表示24个线程中耗时最短的线程耗时情况,Avg、Max等参数以此类推
[gc,phases         ] GC(3308)     Ext Root Scanning (ms):   Min:  3.5, Avg:  5.1, Max:  5.5, Diff:  2.0, Sum: 123.3, Workers: 24
# 记忆集(RSet)更新
[gc,phases         ] GC(3308)     Update RS (ms):           Min:  7.8, Avg: 19.2, Max: 29.9, Diff: 22.2, Sum: 460.8, Workers: 24
[gc,phases         ] GC(3308)       Processed Buffers:        Min: 13, Avg: 107.6, Max: 221, Diff: 208, Sum: 2583, Workers: 24
# Scan Cards
# 这一阶段会从DCQ中找出卡片,遍历其区域中所有对象,用于更新Rset 
[gc,phases         ] GC(3308)       Scanned Cards:            Min: 3316, Avg: 8767.1, Max: 14417, Diff: 11101, Sum: 210411, Workers: 24
[gc,phases         ] GC(3308)       Skipped Cards:            Min: 0, Avg: 10.3, Max: 23, Diff: 23, Sum: 247, Workers: 24
# 扫码Rset
# 这一阶段会将Rset中对象作为根,扫描活跃对象
[gc,phases         ] GC(3308)     Scan RS (ms):             Min:  0.0, Avg:  9.0, Max: 16.2, Diff: 16.2, Sum: 217.0, Workers: 24
[gc,phases         ] GC(3308)       Scanned Cards:            Min: 0, Avg: 4385.7, Max: 8922, Diff: 8922, Sum: 105257, Workers: 24
[gc,phases         ] GC(3308)       Claimed Cards:            Min: 0, Avg: 4892.9, Max: 9695, Diff: 9695, Sum: 117429, Workers: 24
[gc,phases         ] GC(3308)       Skipped Cards:            Min: 0, Avg: 53531.8, Max: 84703, Diff: 84703, Sum: 1284762, Workers: 24
[gc,phases         ] GC(3308)     Code Root Scanning (ms):  Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.1, Workers: 24
[gc,phases         ] GC(3308)     AOT Root Scanning (ms):   skipped
# 对像拷贝
[gc,phases         ] GC(3308)     Object Copy (ms):         Min: 62.5, Avg: 76.7, Max: 98.7, Diff: 36.2, Sum: 1839.7, Workers: 24
[gc,phases         ] GC(3308)     Termination (ms):         Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.4, Workers: 24
[gc,phases         ] GC(3308)       Termination Attempts:     Min: 1, Avg:  1.0, Max: 1, Diff: 0, Sum: 24, Workers: 24
[gc,phases         ] GC(3308)     GC Worker Other (ms):     Min:  0.1, Avg:  0.5, Max:  0.8, Diff:  0.7, Sum: 11.2, Workers: 24
[gc,phases         ] GC(3308)     GC Worker Total (msG):     Min: 110.3, Avg: 110.6, Max: 110.9, Diff:  0.6, Sum: 2655.0, Workers: 24
#  善后工作
[gc,phases         ] GC(3308)   Post Evacuate Collection Set: 3.7ms
[gc,phases         ] GC(3308)     Code Roots Fixup: 0.0ms
[gc,phases         ] GC(3308)     Clear Card Table: 2.1ms
[gc,phases         ] GC(3308)     Reference Processing: 0.3ms
[gc,phases,ref     ] GC(3308)       Reconsider SoftReferences: 0.0ms
[gc,phases,ref     ] GC(3308)         SoftRef (ms):             skipped
[gc,phases,ref     ] GC(3308)       Notify Soft/WeakReferences: 0.1ms
[gc,phases,ref     ] GC(3308)         SoftRef (ms):             Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 1
[gc,phases,ref     ] GC(3308)         WeakRef (ms):             Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 1
[gc,phases,ref     ] GC(3308)         FinalRef (ms):            Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 1
[gc,phases,ref     ] GC(3308)         Total (ms):               Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 1
[gc,phases,ref     ] GC(3308)       Notify and keep alive finalizable: 0.1ms
[gc,phases,ref     ] GC(3308)         Balance queues: 0.0ms
[gc,phases,ref     ] GC(3308)         FinalRef (ms):            Min:  0.0, Avg:  0.1, Max:  0.1, Diff:  0.1, Sum:  1.5, Workers: 24
[gc,phases,ref     ] GC(3308)       Notify PhantomReferences: 0.1ms
[gc,phases,ref     ] GC(3308)         PhantomRef (ms):          Min:  0.1, Avg:  0.1, Max:  0.1, Diff:  0.0, Sum:  0.1, Workers: 1
[gc,phases,ref     ] GC(3308)       SoftReference:
[gc,phases,ref     ] GC(3308)         Discovered: 0
[gc,phases,ref     ] GC(3308)         Cleared: 0
[gc,phases,ref     ] GC(3308)       WeakReference:
[gc,phases,ref     ] GC(3308)         Discovered: 194
[gc,phases,ref     ] GC(3308)         Cleared: 536
[gc,phases         ] GC(3308)     Weak Processing: 0.1ms
[gc,phases         ] GC(3308)       JVMTI weak processing: 0.0ms
[gc,phases         ] GC(3308)       JFR weak processing: 0.0ms
[gc,phases         ] GC(3308)       JNI weak processing       Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.1, Workers: 24
[gc,phases         ] GC(3308)       VM weak processing        Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.9, Workers: 24
[gc,phases         ] GC(3308)     Merge Per-Thread State: 0.1ms
[gc,phases         ] GC(3308)     Code Roots Purge: 0.0ms
[gc,phases         ] GC(3308)     Redirty Cards: 0.4ms
[gc,phases         ] GC(3308)     DerivedPointerTable Update: 0.7ms
[gc,phases         ] GC(3308)     Free Collection Set: 0.5ms
[gc,phases         ] GC(3308)     Humongous Reclaim: 0.2ms
[gc,phases         ] GC(3308)     Start New Collection Set: 0.0ms
[gc,phases         ] GC(3308)     Resize TLABs: 0.3ms
[gc,phases         ] GC(3308)     Resize Heap After Collection: 0.0ms
[gc,phases         ] GC(3308)   Other: 4.3ms
# 各区域变化情况
[gc,heap           ] GC(3308) Eden regions: 1139->0(1136)
[gc,heap           ] GC(3308) Survivor regions: 49->50(149)
[gc,heap           ] GC(3308) Old regions: 784->785
[gc,heap           ] GC(3308) Humongous regions: 53->51
[gc,metaspace      ] GC(3308) Metaspace: 534929K->534929K(561152K)
[gc,heap           ] GC(3308) Heap after GC invocations=3309 (full 0): garbage-first heap   total 36700160K, used 14501693K [0x00007f51e9000000, 0x00007f5aa9000000)
[gc,heap           ] GC(3308)   region size 16384K, 50 young (819200K), 50 survivors (819200K)
[gc,heap           ] GC(3308)  Metaspace       used 534929K, capacity 545739K, committed 559360K, reserved 561152K
# 本次GC总耗时信息
[gc                ] GC(3308) Pause Young (Concurrent Start) (G1 Humongous Allocation) 32394M->14161M(35840M) 119.004ms
[gc,cpu            ] GC(3308) User=2.45s Sys=0.11s Real=0.11s
[safepoint         ] Leaving safepoint region

感言

在本篇文章中,主要向各位介绍来G1的机制原理,篇幅与时间有限,无法在此详述G1调优相关内容,如果大家对此比较感兴趣,后续可能会另写一篇文章,专门介绍G1调优相关的内容,比如说如何设置进入Space Reclamation的阈值,如何控制选择Cset,如何控制TLAB重新申请的时机,GC某个阶段耗时过长如何尝试调优等

参考资料

HotSpot Virtual Machine Garbage Collection Tuning Guide

《JVM G1源码分析和调优》

《深入Java虚拟机:JVM G1GC的算法与实现》

《实战Java虚拟机:JVM故障诊断与性能优化》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一站式元数据治理平台——Datahub

一站式元数据治理平台——Datahub万字保姆级长文——Linkedin元数据管理平台Datahub离线安装指南 - 独孤风 - 博客园 (cnblogs.com)企业级数据治理工作怎么开展?Datahub这样做 - 独孤风 - 博客园 (cnblogs.com)【DataHub】 现代数据栈的元数据平台–如何与spark集成…

如何设计金融机构多场景关键应用下的存储架构

【摘要】银行、保险等金融机构存在多场景下的关键应用,如何选择适合各场景下的存储,如何设计适合业务的存储架构,显得尤为重要。本文从当前主流存储架构分析入手,提出金融机构业务场景分析与架构选型思路,以Glusterfs为例,分享如何根据业务场景的特点,有针对性的选取适合…

SQL优化

文章目录提升group by的效率分页查询优化覆盖索引子查询起始位置重定义检查 where,order by,group by后面的列尽量使用 varchar 代替 char。(SQL 性能优化)如果修改 / 更新数据过多,考虑批量进行提升group by的效率 select user_id,user_nam…

spring-security源码学习总结

由于SpringBoot 对 Security 的支持类均位于org.springframework.boot.autoconfigure.security包下,主要通过 SecurityAutoConfiguration 自动配置类和 SecurityProperties 属性配置来完成,所以需要下载springboot源码深入学习 SecurityAutoConfiguratio…

云原生边缘设备解决方案Akri on k3s初体验

作者: 涂家英,SUSE 资深架构师,专注 Cloud-Native 相关产品和解决方案设计,在企业级云原生平台建设领域拥有丰富的经验。 写在前面 k3s 是 SUSE 推出的为物联网和边缘计算构建的经过认证的 Kubernetes 发行版,它可以帮…

指数函数及其导函数

目录前言指数函数的导函数指数函数导函数动图绘制参考文献前言 前面我们介绍了指数函数及其基本性质以及如何在笛卡尔直角坐标系下绘制静态的指数函数图像,这一节,我们将重点讨论一下指数函数的导函数以及导函数的动态表示,为方便起见&#…

大数据(9f)Flink富函数RichFunction

文章目录1、概述2、示例2.1、普通函数2.2、富函数2.2.1、获取富函数的运行时上下文3、源码截取3.1、RichFunction3.2、RuntimeContext1、概述 Rich Function,译名富函数,和普通函数相比,多了:生命周期(open和close方法…

DGL学习笔记——第二章 消息传递范式

提示:DGL用户指南学习中 文章目录一、内置函数和消息传递API二、编写高效的消息传递代码总结消息传递是实现GNN的一种通用框架和编程范式。它从聚合与更新的角度归纳总结了多种GNN模型的实现。 假设节点 𝑣 上的的特征为 𝑥𝑣∈ℝ…

Java(八)----多线程

1. 线程的基本概念 1.1 进程 任何的软件存储在磁盘(硬盘)中,运行软件的时候,OS(操作系统)使用IO技术,将磁盘中的软件的文件加载到内存,程序才能运行。 (进程是从硬盘到内存) 进程的概念 : 应…

Marked.js让您的文档编辑更加轻松自如!

低代码应用平台——kintone既可以保留更改记录,也有流程管理的功能,在公司内部分享会议记录啊、wiki等文档或学习资料等时非常的便利。 kintone还有丰富的文本编辑框,可以对内容进行编辑提高易读性。但是还是有不少人觉得如果能够使用Markdo…

19.[Python GUI] PyQt5中的模型与视图框架-基本原理

PyQt中的模型与视图框架 一、Qt中模型与视图相关的类 二、模型与视图的基本原理 MVC把图形界面分为三个部分:模型(Model),视图(View)和控制器(Controller), 模型&#x…

Git大型文件存储

什么是 Git LFS? Git 是跟踪代码库演变和与同行高效协作的绝佳选择。但是,当您要跟踪的存储库非常大时会发生什么? 如果您考虑一下,存储库变得庞大的主要原因大致有两个: 他们积累了非常非常长的历史(项目…

【C】文件操作fopen与fclose

目录 函数 1.fopen 2.fclose 3.freopen 函数 头文件 #include<stdio.h> 1.fopen FILE *fopen(const char *restrict dilename,const char* restrict mode); 作用&#xff1a;打开文件参数&#xff1a; 第一个是含有要打开文件名的字符串&#xff08;"文件名…

肝了一周的八万字Redis实战篇

Redis实战篇 文章目录Redis实战篇开篇导读1. 短信登录2. 商户查询缓存3. 优惠卷秒杀4. 附近的商户5. UV统计6. 用户签到7. 好友关注8. 达人探店一、短信登录1. 导入黑马点评项目1.1 导入SQL1.2 有关当前模型1.3 导入后端项目1.4 导入前端工程1.5 运行前端项目2. 基于Session实现…

【杂谈】快来看看如何使用LGMT这样的蜜汁缩写来进行CodeReview吧!

文章目录一、先从一个梗开始说起吧&#xff01;二、什么是LGTM&#xff1f;2.1 LGTM 是什么意思&#xff1f;2.2 蹭梗品牌故事2.3 虚假的CodeReview三、Code Review中的蜜汁缩写四、参考链接一、先从一个梗开始说起吧&#xff01; 公司最近在如火如荼的开展CodeReview活动&…

Reinforcement learning from demonstration through shaping(Wiewiora 2003)

摘要 强化学习中的一个重要问题是如何以有原则的方式整合专家知识&#xff0c;尤其是当我们扩展到现实世界的任务时。在本文中&#xff0c;我们提出了一种在不改变最优策略的情况下将任意建议纳入强化学习agent的奖励结构的方法。 该方法将 Ng 等人 (1999) 提出的基于势能的塑…

1530_AURIX_TriCore内核架构_通用寄存器以及系统寄存器

全部学习汇总&#xff1a; GreyZhang/g_tricore_architecture: some learning note about tricore architecture. (github.com) 继续看一下内核手册&#xff0c;这次了解一下通用寄存器以及系统寄存器。最近一段时间最复位以及trap困扰了许久&#xff0c;看看这里面是否能够获取…

黄河水稻山东智慧 国稻种芯·中国水稻节:济南泉城米袋子

黄河水稻山东智慧 国稻种芯中国水稻节&#xff1a;济南泉城米袋子 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会报道&#xff1a;又是一年春天。济南黄河流域吴家堡水稻田旁的…

数据挖掘与机器学习:数据挖掘算法原理与实践:数据预处理

目录 第一关&#xff1a;标准化 任务描述&#xff1a; 相关知识&#xff1a; 一、为什么要进行标准化 二、Z-score标准化 三、Min-max标准化 四、MaxAbs标准化 编程要求&#xff1a; 测试说明&#xff1a; 第二关&#xff1a;非线性转换 任务描述&#xff1a; 相关知…

【LeetCode】878. 第 N 个神奇数字

题目描述 一个正整数如果能被 a 或 b 整除&#xff0c;那么它是神奇的。 给定三个整数 n , a , b &#xff0c;返回第 n 个神奇的数字。因为答案可能很大&#xff0c;所以返回答案 对 109 7 取模 后的值。 示例 1&#xff1a; 输入&#xff1a;n 1, a 2, b 3 输出&#xff…