g1是java 8u40后默认垃圾回收器,面向大堆低延迟场景,将堆划分为等大region,通过预测停顿模型优先回收高收益region;其流程含初始标记、并发标记、最终标记和筛选回收四阶段;关键参数包括-xx:maxgcpausemillis、-xx:g1heapregionsize等,调优需平衡延迟与吞吐。

G1(Garbage-First)是 Java 8u40 后默认的垃圾回收器,专为大堆(几 GB 到数十 GB)、低延迟场景设计。它不按传统“年轻代/老年代”物理分代,而是把堆划分为多个大小相等的 Region,通过预测停顿时间模型,优先回收垃圾最多、耗时最少的 Region,实现可预测的暂停时间目标。
G1 的核心工作流程
G1 回收不是全堆扫描,而是分阶段、增量式推进:
- 初始标记(Initial Mark):STW 阶段,仅标记 GC Roots 直接可达对象(如线程栈、静态变量),速度很快,通常和 Minor GC 合并执行。
- 并发标记(Concurrent Marking):与应用线程并发运行,遍历对象图,识别存活对象;期间会记录跨 Region 引用(通过 Remembered Set,简称 RSet)。
- 最终标记(Remark):STW 阶段,处理并发标记期间的变动(SATB 写屏障日志),清理引用队列(如 WeakReference)。
- 筛选回收(Cleanup & Evacuation):STW 阶段,统计每个 Region 的存活对象比例和回收收益,按收益排序,选择一组 Region 进行复制清理(Evacuation),将存活对象迁移到新 Region,原 Region 整体释放。
关键调优参数与含义
调优 G1 不是堆参数越多越好,而是围绕停顿时间目标和吞吐量平衡做取舍。以下是最常用且影响直接的参数:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- -XX:+UseG1GC:启用 G1(Java 9+ 默认,但显式声明更清晰)。
- -XX:MaxGCPauseMillis=200:设置期望最大 GC 暂停时间(毫秒),G1 会据此动态调整每次回收的 Region 数量和类型。默认 200ms,建议设为实际业务可容忍的上限(如 100–200ms),不要设得太小(如 50ms),否则会导致频繁回收、吞吐下降甚至 Full GC。
- -Xms 和 -Xmx 设为相同值:避免堆动态扩容缩容带来的额外开销,G1 更适合固定大小堆。
- -XX:G1HeapRegionSize=1M:Region 大小(1–32MB,2 的幂)。默认由堆大小自动推导(约 2048 个 Region)。大对象(>½ Region)会直接进 Humongous 区,易造成碎片;若发现大量 Humongous 分配或回收慢,可适当增大 Region Size(比如堆 16GB 时设为 2M 或 4M)。
- -XX:G1NewSizePercent=20 和 -XX:G1MaxNewSizePercent=50:控制年轻代占堆比例范围(默认 5%–60%,但实际推荐收紧)。G1 动态调整年轻代大小,这两个参数设定边界,防止年轻代过小(导致 Minor GC 频繁)或过大(单次暂停变长)。
- -XX:G1MixedGCCountTarget=8:一次混合回收(Mixed GC)中,目标回收的老年代 Region 数量。值越小,每次 Mixed GC 越激进,但 STW 可能变长;默认 8,一般无需修改,除非观察到老年代回收滞后。
- -XX:G1HeapWastePercent=5:允许堆中被认定为“浪费”的空间占比(如 Humongous 碎片、RSet 开销等)。超过则触发 Mixed GC。默认 5%,若频繁 Mixed GC 但回收不多,可适当调高(如 10)。
常见问题与调优方向
遇到 GC 问题,先用 JVM 参数采集日志,再针对性分析:
- 频繁 Young GC + 暂停略长:检查是否分配速率过高(如短生命周期对象暴增)、Eden 区偏小。可适当提高 -XX:G1NewSizePercent,或降低 -XX:MaxGCPauseMillis 让 G1 分配更多 Region 给年轻代。
- Mixed GC 频率高但老年代没明显下降:说明老年代存活对象多,或 RSet 占用大。用 -XX:+PrintGCDetails -Xlog:gc*:file=gc.log:time 查看 “Humongous allocations” 和 “Remembered Set” 大小;考虑减少大对象创建,或增大 G1HeapRegionSize。
- 发生 Full GC:G1 中 Full GC 是严重信号,常见原因包括并发标记失败(Concurrent Mode Failure)、晋升失败(Evacuation Failure)、Humongous 分配失败。优先检查日志中的触发原因,再对应优化:增加堆、调高 -XX:ConcGCThreads、降低分配速率、或避免超大对象。
- 停顿时间达标但吞吐下降:可能因 -XX:MaxGCPauseMillis 设得太保守,G1 过度拆分回收任务。可适度放宽目标(如从 100ms 放宽到 150ms),观察吞吐与延迟的平衡点。
实用建议与工具辅助
调优不是一锤定音,而是观测 → 假设 → 验证的循环:
- 开启详细 GC 日志:-Xlog:gc*:file=gc.log:time,uptime,level,tags -Xlog:safepoint(Java 10+);旧版本用 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log。
- 用 jstat -gc
实时查看 GC 频率、各区域使用量、停顿时间分布。 - 可视化分析推荐 GCViewer 或 GCEasy,能快速识别 Mixed GC 比例、Humongous 占比、停顿毛刺等问题。
- 压测环境必须模拟真实流量和对象生命周期,避免仅靠启动后空跑调参。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










