- 背景和价值
- 1 不要设置 -xmn来指定新生代堆内存,这种做法存在因为堆内存预估失败而导致的响应时间激增的问题。
- 5 停顿时间。-XX:MaxGCPauseMillis 默认200ms,对响应时间敏感的应用(如 Web 应用、金融交易系统)可设置更低的值
- 6 Region大小设置。较大的 Region 可以减少内存碎片,但可能会增加垃圾回收的粒度。
- 7 设置 Mixed GC 的阈值,如果老年代占用堆内存的比例超过该阈值,G1 会启动 Mixed GC。如果应用有大量长期存活对象,可以适当降低该值。
- -XX:InitiatingHeapOccupancyPercent
- -XX:+UseStringDeduplication
- G1垃圾回收生命周期
- 1. 年轻代回收(Young GC)
- 2. 并发标记周期(Concurrent Marking Cycle)
- 3. 混合回收(Mixed GC)
- 4. 完全垃圾回收(Full GC)
- 生命周期流程图
- 关键注意事项
- 参考资料
背景和价值
1 不要设置 -xmn来指定新生代堆内存,这种做法存在因为堆内存预估失败而导致的响应时间激增的问题。
-XX:G1NewSizePercent(新生代占用堆内存的最小比,默认为5%)以及-XX:G1MaxNewSizePercent(新生代占用堆内存的最大比,默认为60%)
新时代老年代占比。默认新时代占60%,如果应用有大量短期对象,可以适当增加年轻代的大小。
5 停顿时间。-XX:MaxGCPauseMillis 默认200ms,对响应时间敏感的应用(如 Web 应用、金融交易系统)可设置更低的值
6 Region大小设置。较大的 Region 可以减少内存碎片,但可能会增加垃圾回收的粒度。
6.1 堆内存大小与 Region 大小的关系。如果堆内存较小,Region 大小应该相应减小;如果堆内存较大,Region 大小可以适当增大。
6.2 如果应用程序中经常会产生大对象(如大于 Region 大小一半的对象),需要确保 Region 大小能够容纳这些大对象。否则,G1 可能需要使用多个 Region 来存放一个大对象,这会增加内存管理的复杂性和垃圾回收的难度。
7 设置 Mixed GC 的阈值,如果老年代占用堆内存的比例超过该阈值,G1 会启动 Mixed GC。如果应用有大量长期存活对象,可以适当降低该值。
Mixed GC 负责回收老年代 Region
Mixed GC 负责回收老年代 Region,关键参数:
-XX:G1MixedGCLiveThresholdPercent
仅回收存活对象比例低于此值的 Region(默认 85%):-XX:G1MixedGCLiveThresholdPercent=80-XX:G1HeapWastePercent
允许的堆浪费比例,达到该值会触发 Mixed GC(默认 5%):-XX:G1HeapWastePercent=10-XX:G1MixedGCCountTarget
单次 Mixed GC 的回收轮次(默认 8),增大此值可减少单次停顿时间:-XX:G1MixedGCCountTarget=16
-XX:InitiatingHeapOccupancyPercent
触发并发标记周期的堆占用阈值(默认 45%)。如果 Full GC 频繁,可适当降低该值:
避免Full GC,因为G1的设计目标之一就是减少Full GC的发生。这时候需要确保堆足够大,或者调整InitiatingHeapOccupancyPercent,避免过早触发并发周期。
例
-XX:InitiatingHeapOccupancyPercent=35
- 当整个堆占用超过某个百分比时,就会触发并发GC周期,这个百分比默认是45%,我的理解来说,如果你的项目没有大的cpu负载压力,可以适当降低这个值,带来的好处就是提前开始Concurrent Marking Cycle Phases ,进一步来说,回收 年轻代 and 老年代 也会提前开始,这样有利于防止年轻代晋升老年代失败(老年代容量不足)而触发Full GC。
经过观察发现如果这个数值设定过大会导致JVM无法启动并发标记,直接进行FullGC处理。G1的FullGC是单线程,一个22G的对GC完成需要8S的时间,所以这个值在调优的时候写的45%
-XX:+UseStringDeduplication
最近的一项研究表明,应用程序 13.5% 的内存中存在重复的字符串。当你传递 “-XX:+UseStringDeduplication” 参数时,G1 垃圾收集器(G1 GC)提供了一种消除重复字符串的选项。
以上大部分参数要根据实际业务压测。
G1垃圾回收生命周期
Java G1(Garbage-First)垃圾回收器的生命周期包含多个阶段,按触发顺序和执行流程可分为以下核心阶段:
1. 年轻代回收(Young GC)
- 触发条件:Eden 区内存不足时(常规的年轻代回收)。
- 执行过程:
- STW 暂停:暂停所有应用线程(Stop-The-World)。
- 复制存活对象:将 Eden 区和 Survivor 区的存活对象复制到新的 Survivor 区或直接晋升到老年代。
- 调整 Region 归属:回收后的 Eden 区变为空闲 Region。
- 特点:仅处理年轻代 Region,速度快但频率高。
2. 并发标记周期(Concurrent Marking Cycle)
- 触发条件:老年代占用达到 IHOP 阈值(默认 45%,通过
-XX:InitiatingHeapOccupancyPercent调整)。 - 分阶段执行:
- (1) 初始标记(Initial Mark)
- STW 暂停:标记从 GC Roots 直接可达的对象(与 Young GC 同步触发)。
- (2) 根区域扫描(Root Region Scanning)
- 并发执行:扫描 Survivor 区(根区域)中引用到老年代的对象。
- (3) 并发标记(Concurrent Marking)
- 并发执行:遍历堆,标记所有存活对象(与应用线程并行)。
- (4) 最终标记(Remark)
- STW 暂停:处理并发标记期间的变化(SATB 算法修正)。
- (5) 清理(Cleanup)
- STW 暂停:统计每个 Region 的存活对象占比,为混合回收做准备。
- (1) 初始标记(Initial Mark)
- 目标:识别老年代中可回收的 Region(标记垃圾占比高的 Region)。
3. 混合回收(Mixed GC)
- 触发条件:并发标记周期完成后(清理阶段结束)。
- 执行过程:
- STW 暂停:暂停应用线程。
- 混合回收:同时回收年轻代 Region(Eden/Survivor)和标记出的老年代 Region。
- 多轮执行:通过
-XX:G1MixedGCCountTarget控制单次混合回收的轮次(默认 8 轮)。
- 特点:兼顾年轻代和老年代回收,减少 Full GC 风险。
4. 完全垃圾回收(Full GC)
- 触发条件(需尽量避免):
- 并发模式失败:并发标记未完成时堆已满。
- 晋升失败:存活对象无法晋升到老年代。
- 大对象分配失败:Humongous 对象找不到连续 Region。
- 执行过程:
- 单线程 STW 暂停:串行回收整个堆(类似 Serial GC),性能极差。
- 优化方向:通过调整
IHOP、G1ReservePercent等参数避免触发。
生命周期流程图
Young GC(常规) → [IHOP 阈值触发] → 并发标记周期 → Mixed GC → Young GC(循环) ↓ Full GC(异常兜底)
关键注意事项
- 并发标记周期是混合回收的前置条件,只有完成标记才能确定老年代可回收 Region。
- Mixed GC 是增量回收:通过多轮回收分摊停顿时间。
- Full GC 是最后的兜底机制,需通过监控(如 GC 日志)提前规避。
通过调整 -XX:MaxGCPauseMillis(目标停顿时间)和 -XX:G1MixedGCLiveThresholdPercent(回收阈值),可优化混合回收的效率和频率。
