Post

JVM G1垃圾回收器简介与常用配置

简介

G1 is a generational, incremental, parallel, mostly concurrent, stop-the-world, and evacuating garbage collector which monitors pause-time goals in each of the stop-the-world pauses.

在内存空间划分上,G1将堆分为等大的一块区域(region),region是内存分配和垃圾回收的基本单位,其大小为2的幂,范围是 1 MB 到 32 MB 之间,可通过-XX:G1HeapRegionSize=4M进行配置。

G1在逻辑上将堆分为年轻代和老年代两种逻辑类型,年轻代又包含 eden regionsurvivor region ,所有新建的对象均创建在eden region中,在经过young gc后,对象被复制整理到survivor region中(年龄不够到老年代时); 老年代包含可横跨多个region的 humongous区域,大对象指的是超过Region Size 一半大小的对象,这样的对象多了会造成 Heap 空间碎片化。示意图如下:

heap


对象何时进入老年代:

  1. 存活对象超过年龄阈值(默认 15)仍未被回收则进入老年代:熬过一次 GC 增加一岁,默认年龄超过 15 岁还没有被回收则被移动到老年代,通过设置 jvm 参数 -XX:MaxTenuringThreshold 来设置对象进入老年代的阈值;
  2. 大对象直接进入老年代:超过 G1HeapRegionSize 的一半会被认为是大对象,大对象直接进入老年代;
  3. 动态年龄判断:在survivor区中,所有年龄的对象的所占空间的累加和大于survivor空间的百分之-XX:TargetSurvivorRatio值(默认50),大于或等于最大年龄的对象,都可以进入老年代;可参考:JVM-对象什么时候进入老年代(实战篇)
  4. 空间分配担保:young GC 后,survivor 区空间不能容纳全部存活对象;

G1 垃圾回收器包含两个阶段,G1会在这两个阶段循环:

  • Young-only phase: 首先年轻代执行Normal类型垃圾回收,并不断提升对象到老年代,当老年代占用达到the Initiating Heap Occupancy threshold后,G1开启Concurrent Start垃圾回收,这两个阶段不会STW,接下来的Remark和Clean动作真正执行清理工作,会STW
  • Space Reclamation phase: 该阶段包含多种 Mixed 垃圾回收(包含年轻代垃圾回收),会清理老年代对象。

作为兜底,如果G1发现堆内存不够用时会触发Full GC。

  • Remember Set : 当前Region使用 Remember Set 记录其他Region到当前Region的引用,当前Region发生GC时,这些引用需要更新指向。
  • Collection Set : 待回收Region集合

参考: Garbage-First Garbage Collector

参数配置

G1 GC需要配置参数:-XX:+UseG1GC 开启

堆内存配置

1
-Xms8G -Xmx8G -Xss512K -XX:+UnlockExperimentalVMOptions -XX:G1MaxNewSizePercent=40
配置说明建议
-Xms8G堆内存最小值一般为pod内存的80%
-Xmx8G堆内存最大值一般为pod内存的80%
-Xss512K线程栈大小,默认1M512K或1M
-XX:G1NewSizePercent=30年轻代占整个堆的比例最小值 (需开启-XX:+UnlockExperimentalVMOptions)对于启动pod时获取缓存的场景, 可适当调大, 减少启动阶段的频繁调整
-XX:G1MaxNewSizePercent=40年轻代占整个堆已使用的比例最大值 (需开启-XX:+UnlockExperimentalVMOptions)大堆建议调小阈值(>=32G), 降低单次年轻代回收的STW时间
-XX:G1HeapRegionSize=4MG1 Region的大小. 值是 2 的幂, 范围是 1 MB 到 32 MB 之间小堆且常态有持续大对象产生的场景, 可适当调大

关于Region Size可参考:

Heap SizeRegion Size
heap < 4GB1MB
4GB <= heap < 8GB2MB
16GB <= heap < 32GB8MB
32GB <= heap < 64GB16MB
64GB <= heap32MB

GC配置

1
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=50 -XX:MaxTenuringThreshold=10
配置说明建议
-XX:+UseG1GC开启G1垃圾回收 
-XX:MaxGCPauseMillis=100预期GC STW时间,单位ms看场景,低时延的可配置到100ms以内,最大不超过500ms
-XX:InitiatingHeapOccupancyPercent=50触发GC标记周期的堆占用百分比大堆(>=32GB)时适当调大阈值, 减少标记触发
-XX:G1HeapWastePercent=10默认值 : 10% , 堆浪费百分比, 当G1发现可被回收的空间小于10%时, 就不会再进行混合收集, 也就是会结束当前的混合收集周期 
-XX:G1OldCSetRegionThresholdPercent=10默认值 : 堆的5%, 设置混合垃圾回收期间要回收的最大旧区域数占整个堆的百分比 
-XX:G1MixedGCLiveThresholdPercent=70默认值 : 65%, MixGC时, 年老代Region中存活对象百分比, 只有在此阈值下的Region才会被选入回收列表CSet (需开启-XX: +UnlockExperimentalVMOptions )大堆(>=32GB)时适当调大阈值, 增加扫描年老带Region的备选集合, 增加年老代回收效率
-XX:G1MixedGCCountTarget=8最多8次混合垃圾回收, 设置标记周期完成后, 对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数 
-XX:MaxTenuringThreshold=n默认值15, 对象进入年老带前在Survivor区中的最大存活年龄survivor区过大时, 可以跟进GC Log分析分代存活分布, 适当调小阈值, 减轻复制压力, 让对象快速进入年老代,降低young gc压力.

NMT

1
-XX:NativeMemoryTracking=detail
配置说明建议
-XX:NativeMemoryTracking默认值 : 关闭 [summary/detail] , 用于堆外内存泄露分析 

GC日志配置

1
2
3
4
// Java8:
-XX:+PrintGCCause -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution -XX:+PrintReferenceGC -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=2M
// Java11以上:
-Xlog:gc*=info,phases*=debug,region*=debug,age*=trace,ergo*=debug,safepoint,heap*=debug:file=gc.log:time,level,tags:filecount=5,filesize=2m
配置说明建议
-XX:+PrintGCCause打印触发GC的原因默认开启
-XX:+PrintGCDetails打印GC各阶段详细日志默认开启
-XX:+PrintGCApplicationConcurrentTime打印GC并行处理时间不开启
-XX:+PrintGCApplicationStoppedTime打印GC STW时间默认开启
-XX:+PrintAdaptiveSizePolicy打印自适应分代调整信息默认开启
-XX:+PrintTenuringDistribution打印GC扫描存活对象年龄分布默认开启
-XX:+PrintReferenceGC打印引用GC处理详情默认开启
-XX:+PrintGCDateStamps打印GC绝对日期, 默认为从JVM开始的相对时间戳默认开启
-XX:+PrintGCTimeStamps打印GC绝对时间, 默认为从JVM开始的相对时间戳默认开启
-XX:+PrintHeapAtGC打印GC前后堆内存详情默认开启

其他

配置说明建议
-XX:-UseBiasedLocking默认值 : 偏向锁开启。当锁竞争不激烈时可以通过偏向来提高性能. 但是高并发的情况下, 偏向锁会经常失效, 取消偏向锁时, 需要获取每个线程使用锁的状态以及运行状态,该过程会STW 
-XX:-OmitStackTraceInFastThrow默认值 : 开启同一位置不断抛出同样的Exception, JIT会丢弃原始堆栈和Message来提升性能. 无脑关闭

配置参考

规格实例配置参数
1C2G-Xmx1G -Xms1G -Xss256K -XX:MaxMetaspaceSize=320M -XX:MetaspaceSize=320M -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:ParallelGCThreads=1 -XX:ConcGCThreads=1 -XX:InitiatingHeapOccupancyPercent=50 -XX:-OmitStackTraceInFastThrow -XX:+ParallelRefProcEnabled -XX:+PrintGCDetails -XX:+PrintGCDateStamps
4C8G-Xmx6G -Xms6G -Xss512K -XX:MaxMetaspaceSize=320M -XX:MetaspaceSize=320M -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:ParallelGCThreads=4 -XX:ConcGCThreads=1 -XX:InitiatingHeapOccupancyPercent=50 -XX:-OmitStackTraceInFastThrow -XX:+ParallelRefProcEnabled -XX:+PrintGCDetails -XX:+PrintGCDateStamps
8C16G-Xmx12G -Xms12G -Xss512K -XX:MaxMetaspaceSize=320M -XX:MetaspaceSize=320M -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=40 -XX:-OmitStackTraceInFastThrow -XX:+ParallelRefProcEnabled -XX:+PrintGCDetails -XX:+PrintGCDateStamps
This post is licensed under CC BY 4.0 by the author.