java9系列(九)Make G1 the Default Garbage Collector

codecraft

本文主要研究下JEP 248: Make G1 the Default Garbage Collector

默认垃圾收集器

java9废弃了CMS垃圾收集器,并把G1提升为默认垃圾收集器,替代了原来的吞吐优先的ParallelOldGC

Region

G1相对于之前的垃圾收集器最大的不同是引入了Region。G1虽然也是基于分代机制,但是各个generation的空间不再连续,如下图:

可以用-XX:G1HeapRegionSize=16m来指定Region Size,注意它必须是2的乘方,范围在1MB到32MB之间。目标是根据最小的Java堆大小划分出约2048 个区域.

如果没有明确指定,则自动根据Heap Size来指定,其对应关系如下:

Min Heap Size Region Size
heap < 4GB 1MB
4GB <= heap < 8GB 2MB
8GB <= heap < 16GB 4MB
16GB <= heap < 32GB 8MB
32GB <= heap < 64GB 16MB
64GB <= heap 32MB

Humongous Object/ Humongous区域

  • 对于G1 GC,任何超过区域一半大小的对象都被视为“巨型对象”。
  • 此类对象直接被分配到老年代中的“巨型区域”。
  • 这些巨型区域是一个连续的区域集。StartsHumongous 标记该连续集的开始,ContinuesHumongous 标记它的延续。
巨型对象默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

GC事件及触发

GC event

  • Minor GC event
正常的young gc
  • Mixed GC event
Minor GC + (# reclaimable Tenured regions / -XX:G1MixedGCCountTarget) regions of Tenured
  • Full GC event
All regions evacuated,通常Humongous object太多会耗尽空间,导致Full GC
  • Minor/Mixed + To-space exhaustion
Minor/Mixed + rollback + Full GC

触发时机

  • Eden满/空间不够
  • 剩余空间不够容纳一个Humongous object
  • Humongous object分配成功,同时符合一些GC条件
  • 外部命令触发(jcmd, jmap, Runtime.gc())

G1 GC分类

主要分为:Minor GC,Mixed/Old GC

Minor GC/Young GC(STW)

Young GC主要是对Eden区进行GC,它在Eden空间不够时会被触发。Eden空间的数据移动到Survivor空间中,如果Survivor空间不够,Eden空间的部分数据会直接晋升到年老代空间。From Survivor区的数据移动到To Survivor区中,也有部分数据晋升到老年代空间中。

其阶段主要如下:

阶段 执行动作
阶段1 根扫描 静态和本地对象被扫描
阶段2 更新RS 处理dirty card队列更新RS
阶段3 处理RS 检测从年轻代指向年老代的对象
阶段4 对象拷贝 拷贝存活的对象到survivor/old区域
阶段5 处理引用队列 软引用,弱引用,虚引用处理

Mixed/Old GC(STW)

主要是对年老代进行并发标记然后进行GC,其中部分阶段涉及到ygc,同时既有ygc及old gc的部分称为mixed gc。

并发标记周期(Concurrent Marking Cycle Phases)阶段如下:

阶段 执行动作
(1) Initial Mark(Stop the World Event) 初始标记阶段 在此阶段G1 GC对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。日志标记为Pause Initial Mark (G1 Evacuation Pause).
(2) Root Region Scanning 根区域扫描阶段 G1 GC在初始标记的存活区扫描对老年代的引用,并标记被引用的对象。该阶段与应用程序(非 STW)同时运行,并且只有完成该阶段后,才能开始下一次STW年轻代垃圾回收。
(3) Concurrent Marking 并发标记阶段 G1 GC在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断。
(4) Remark(Stop the World Event) 重新标记阶段 该阶段是STW回收,帮助完成标记周期。G1 GC清空SATB缓冲区,跟踪未被访问的存活对象,并执行引用处理。
(5) Copying(Stop the World Event) / Cleanup(Stop the World Event and Concurrent) 拷贝/清理阶段 在这个最后阶段,G1 GC为了更快进行垃圾回收,会选择那些存活率低的region进行拷贝,即evacuate或者拷贝存活对象到新的空闲的regions,然后清理回收该region,此时会STW,如果是在年轻代产生的,则日志标记为Pause Young (G1 Evacuation Pause),如果年轻代和年老代都进行这个动作,则日志标记为Pause Mixed (G1 Evacuation Pause).
核心的阶段主要是Concurrent Marking Phase、Remark Phase、Copying/Cleanup Phase

相关参数

参数 含义
-XX:G1HeapRegionSize=n 设置Region大小,并非最终值
-XX:MaxGCPauseMillis=200 设置G1收集过程目标时间,默认值200ms,不是硬性条件
-XX:G1NewSizePercent=5 新生代最小值,默认值5%
-XX:G1MaxNewSizePercent=60 新生代最大值,默认值60%
-XX:ParallelGCThreads=n STW期间,并行GC线程数,其值与逻辑处理器的数量相同,最多为8。如果逻辑处理器不止八个,则将n为逻辑处理器数的5/8
-XX:ConcGCThreads=n 并发标记阶段的并行标记线程数,ParallelGCThreads的 1/4 左右
-XX:InitiatingHeapOccupancyPercent=45 设置触发标记周期的Java堆占用率阈值。默认值是45%。这里的java堆占比指的是non_young_capacity_bytes,包括old+humongous
-XX:G1MixedGCLiveThresholdPercent=65 为混合垃圾回收周期中要包括的旧区域设置占用率阈值。默认占用率为 65%
-XX:G1HeapWastePercent=10 如果可回收百分比小于此值,JVM不会启动混合垃圾回收周期。默认值是10%
-XX:G1OldCSetRegionThresholdPercent=10 设置混合垃圾回收期间要回收的最大旧区域数。默认值是Java堆的10%
-XX:G1MixedGCCountTarget=8 设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数。默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内
-XX:G1ReservePercent=10 设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险。默认值是10%。增加或减少百分比时,请确保对总的Java 堆调整相同的量
避免使用-Xmn选项或-XX:NewRatio等其他相关选项显式设置年轻代大小,固定年轻代的大小会禁用掉暂停时间(MaxGCPauseMillis)目标。

GC日志实例

简版使用-Xlog:gc=info,详细版使用-Xlog:gc*=info

ygc

  • 简版
[0.317s][info][gc] GC(37) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.511ms
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
  • 详细版
[0.011s][info][gc,heap] Heap region size: 1M
[0.012s][info][gc     ] Using G1
[0.012s][info][gc,heap,coops] Heap address: 0x00000007bf600000, size: 10 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.170s][info][gc,start     ] GC(0) Pause Young (G1 Evacuation Pause)
[0.170s][info][gc,task      ] GC(0) Using 8 workers of 8 for evacuation
[0.172s][info][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[0.172s][info][gc,phases    ] GC(0)   Evacuate Collection Set: 1.5ms
[0.172s][info][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.1ms
[0.172s][info][gc,phases    ] GC(0)   Other: 0.1ms
[0.172s][info][gc,heap      ] GC(0) Eden regions: 4->0(2)
[0.172s][info][gc,heap      ] GC(0) Survivor regions: 0->1(1)
[0.172s][info][gc,heap      ] GC(0) Old regions: 0->1
[0.172s][info][gc,heap      ] GC(0) Humongous regions: 0->0
[0.172s][info][gc,metaspace ] GC(0) Metaspace: 5982K->5982K(1056768K)
[0.172s][info][gc           ] GC(0) Pause Young (G1 Evacuation Pause) 4M->1M(10M) 1.718ms
[0.172s][info][gc,cpu       ] GC(0) User=0.01s Sys=0.00s Real=0.00s

old gc

  • 简版
[0.321s][info][gc] GC(38) Pause Initial Mark (G1 Evacuation Pause) 7M->6M(10M) 0.601ms
[0.321s][info][gc] GC(39) Concurrent Cycle
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
[0.326s][info][gc] GC(39) Pause Remark 7M->7M(10M) 0.623ms
[0.326s][info][gc] GC(39) Pause Cleanup 7M->7M(10M) 0.104ms
[0.326s][info][gc] GC(39) Concurrent Cycle 5.398ms
[0.327s][info][gc] GC(41) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.512ms
[0.331s][info][gc] GC(42) To-space exhausted
[0.331s][info][gc] GC(42) Pause Mixed (G1 Evacuation Pause) 7M->7M(10M) 1.190ms
[0.334s][info][gc] GC(43) Pause Initial Mark (G1 Evacuation Pause) 8M->7M(10M) 0.637ms
[0.334s][info][gc] GC(44) Concurrent Cycle
[0.338s][info][gc] GC(45) Pause Young (G1 Evacuation Pause) 8M->7M(10M) 0.553ms
[0.340s][info][gc] GC(44) Pause Remark 8M->8M(10M) 0.582ms
[0.341s][info][gc] GC(44) Pause Cleanup 8M->8M(10M) 0.100ms
[0.341s][info][gc] GC(44) Concurrent Cycle 6.195ms
  • 详细版
[0.942s][info][gc,start       ] GC(192) Pause Initial Mark (G1 Evacuation Pause)
[0.942s][info][gc,task        ] GC(192) Using 8 workers of 8 for evacuation
[0.942s][info][gc,phases      ] GC(192)   Pre Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases      ] GC(192)   Evacuate Collection Set: 0.4ms
[0.942s][info][gc,phases      ] GC(192)   Post Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases      ] GC(192)   Other: 0.0ms
[0.942s][info][gc,heap        ] GC(192) Eden regions: 0->0(1)
[0.942s][info][gc,heap        ] GC(192) Survivor regions: 0->0(1)
[0.942s][info][gc,heap        ] GC(192) Old regions: 10->10
[0.942s][info][gc,heap        ] GC(192) Humongous regions: 0->0
[0.942s][info][gc,metaspace   ] GC(192) Metaspace: 5993K->5993K(1056768K)
[0.942s][info][gc             ] GC(192) Pause Initial Mark (G1 Evacuation Pause) 9M->9M(10M) 0.530ms
[0.942s][info][gc,cpu         ] GC(192) User=0.00s Sys=0.00s Real=0.00s
[0.942s][info][gc             ] GC(193) Concurrent Cycle
[0.942s][info][gc,marking     ] GC(193) Concurrent Clear Claimed Marks
[0.942s][info][gc,marking     ] GC(193) Concurrent Clear Claimed Marks 0.004ms
[0.942s][info][gc,marking     ] GC(193) Concurrent Scan Root Regions
[0.942s][info][gc,marking     ] GC(193) Concurrent Scan Root Regions 0.003ms
[0.942s][info][gc,marking     ] GC(193) Concurrent Mark (0.942s)
[0.942s][info][gc,marking     ] GC(193) Concurrent Mark From Roots
[0.942s][info][gc,task        ] GC(193) Using 2 workers of 2 for marking
[0.942s][info][gc,start       ] GC(194) Pause Full (Allocation Failure)
[0.943s][info][gc,phases,start] GC(194) Phase 1: Mark live objects
[0.946s][info][gc,stringtable ] GC(194) Cleaned string and symbol table, strings: 3222 processed, 0 removed, symbols: 25923 processed, 0 removed
[0.946s][info][gc,phases      ] GC(194) Phase 1: Mark live objects 3.168ms
[0.946s][info][gc,phases,start] GC(194) Phase 2: Compute new object addresses
[0.946s][info][gc,phases      ] GC(194) Phase 2: Compute new object addresses 0.418ms
[0.946s][info][gc,phases,start] GC(194) Phase 3: Adjust pointers
[0.949s][info][gc,phases      ] GC(194) Phase 3: Adjust pointers 2.706ms
[0.949s][info][gc,phases,start] GC(194) Phase 4: Move objects
[0.949s][info][gc,phases      ] GC(194) Phase 4: Move objects 0.005ms
[0.949s][info][gc,task        ] GC(194) Using 8 workers of 8 to rebuild remembered set
[0.951s][info][gc,heap        ] GC(194) Eden regions: 0->0(1)
[0.951s][info][gc,heap        ] GC(194) Survivor regions: 0->0(1)
[0.951s][info][gc,heap        ] GC(194) Old regions: 10->10
[0.951s][info][gc,heap        ] GC(194) Humongous regions: 0->0
[0.951s][info][gc,metaspace   ] GC(194) Metaspace: 5993K->5993K(1056768K)
[0.951s][info][gc             ] GC(194) Pause Full (Allocation Failure) 9M->9M(10M) 8.955ms
[0.951s][info][gc,cpu         ] GC(194) User=0.01s Sys=0.00s Real=0.01s

小结

G1收集器博大精深,有待进一步实践进行深入理解研究。

doc

阅读 2.8k

code-craft
spring boot , docker and so on 欢迎关注微信公众号: geek_luandun

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下了或重如泰山或轻如鸿毛的几笔。

11.3k 声望
1.1k 粉丝
0 条评论

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下了或重如泰山或轻如鸿毛的几笔。

11.3k 声望
1.1k 粉丝
宣传栏