深入解析 G1 垃圾回收器:Region、Remembered Set 与 Mixed GC 全揭秘(附 CMS 对比)

📅 发布时间:2026/7/3 5:52:35 👁️ 浏览次数:
深入解析 G1 垃圾回收器:Region、Remembered Set 与 Mixed GC 全揭秘(附 CMS 对比)
在 Java 高并发、大内存应用中垃圾回收GC性能直接影响系统稳定性与用户体验。从 JDK 9 开始G1Garbage-First成为默认垃圾回收器取代了曾经的 CMS。那么G1 到底强在哪里它是如何做到低停顿、高吞吐、避免内存碎片的本文将用通俗语言 图解思维 实战配置带你彻底搞懂 G1 的核心机制并对比 CMS让你明白为什么 G1 是现代 Java 应用的首选一、为什么需要 G1传统回收器的痛点在 G1 出现前主流回收器有Parallel GC吞吐量高但 Full GC 停顿时间长秒级不适合低延迟场景。CMSConcurrent Mark-Sweep并发回收停顿短但存在严重内存碎片且无法预测停顿时间。G1 的设计目标可预测的停顿时间如 ≤ 200ms高吞吐避免内存碎片适用于大堆内存4GB~TB 级二、G1 的核心思想化整为零 —— Region 划分✅ 什么是 RegionG1 将整个堆内存划分为多个大小相等的 Region默认约 2048 个每个 1~32MB由堆大小决定。[ Eden ] [ Eden ] [ Survivor ] [ Old ] [ Humongous ] ...Eden Region新对象分配Survivor RegionYoung GC 后存活的对象Old Region长期存活对象Humongous Region存储超大对象 Region 50%可能占用连续多个 Region 关键突破不再区分连续的新生代/老年代空间而是用逻辑标签标记 Region 角色。 Region 的优势回收时只选择部分 Region“Garbage-First”而非整个老年代可灵活控制回收范围实现停顿时间可预测三、跨代引用难题Remembered SetRSet的作用❓ 问题如何高效追踪 Old → Young 的引用在分代 GC 中Young GC 需要知道哪些 Old 对象引用了 Young 对象否则会误删。传统方案需扫描整个老年代代价巨大。✅ G1 的解决方案Remembered SetRSet每个 Region 都有一个 RSetRSet 记录其他 Region 中指向本 Region 的对象卡表Card Table索引Young GC 时只需扫描Eden/Survivor Region 的 RSet无需遍历整个 Old 区Region A (Old) ────引用───→ Region B (Eden) ↓ RSet of B: 记录 Region A, Card #123⚡ 效果Young GC 停顿时间与堆大小无关只与活跃对象数和 RSet 大小相关四、G1 垃圾回收的两大阶段1️⃣ Young GC年轻代回收触发条件Eden 区满过程暂停所有应用线程STW扫描Eden Survivor Region将存活对象复制到新的 Survivor 或 Old Region清空原 Eden/Survivor Region变为空闲 Region✅ 特点停顿时间短通常几十毫秒使用复制算法无碎片2️⃣ Mixed GC混合回收触发条件完成一次并发标记周期Concurrent Marking Cycle老年代占用达到IHOPInitiating Heap Occupancy Percent默认 45%过程并发标记阶段与应用并发执行初始标记STW并发标记遍历对象图最终标记STW修正并发期间变化Mixed GC 阶段多次 STW选择垃圾比例最高的若干 Old Region 所有 Young Region复制存活对象释放空间✅ 关键优先回收垃圾最多的 Region“Garbage-First” 名字来源 G1 通过-XX:G1MixedGCCountTarget默认 8控制 Mixed GC 次数逐步清理老年代。五、G1 vs CMS两大关键改进维度CMSG1G1 的优势内存碎片使用标记-清除算法产生大量碎片可能导致 Full GC使用复制算法回收后 Region 完全清空无碎片✅ 避免因碎片触发 Full GC停顿时间预测无法预测Concurrent Mode Failure 时退化为 Serial GC秒级停顿通过Region 选择 停顿预测模型可设置-XX:MaxGCPauseMillis200目标值✅可预测、可控的低延迟 举例说明CMS 场景老年代碎片化严重 → 即使总空闲空间足够也无法分配大对象 → 触发 Full GC → 应用停顿 2 秒G1 场景每次 Mixed GC 都整理内存 → Region 始终紧凑 → 大对象可直接分配到 Humongous Region →永不因碎片 Full GC六、Spring Boot 应用 G1 调优建议实战配置# application-prod.ymlJVM 参数建议 java: opts: -server -Xms8g -Xmx8g -XX:UseG1GC -XX:MaxGCPauseMillis200 # 目标停顿时间 -XX:G1HeapRegionSize4m # 显式设置 Region 大小可选 -XX:G1NewSizePercent20 # Eden 最小占比 -XX:G1MaxNewSizePercent40 # Eden 最大占比 -XX:G1ReservePercent10 # 保留内存防晋升失败 -XX:G1HeapWastePercent5 # 允许浪费的堆比例 -XX:G1PrintRegionLivenessInfo # 打印 Region 存活信息调试用调优口诀“设目标停顿控 Region 选择防晋升失败避 Humongous 滥用”七、反例警示这些用法会让 G1 性能暴跌❌ 反例1堆太小 4GBG1 适合大堆小堆下 Region 管理开销反而高于 Parallel GC。✅ 建议堆 ≥ 4GB 再考虑 G1。❌ 反例2频繁创建超大对象// 错误每次 new byte[100 * 1024 * 1024]100MB byte[] huge new byte[100_000_000];→ 触发Humongous Allocation占用多个连续 Region回收效率低。✅ 建议复用缓冲区或使用堆外内存如 Netty ByteBuf。❌ 反例3忽略 IHOP 导致 Mixed GC 延迟默认IHOP45%若老年代增长快可能来不及回收就 OOM。✅ 调优-XX:InitiatingHeapOccupancyPercent30 # 提前触发并发标记八、总结G1 为何成为现代 Java 默认 GC特性G1 实现方式低停顿分 Region 回收 停顿预测模型无碎片复制算法 Region 整体释放大堆友好并发标记 混合回收可配置性强通过MaxGCPauseMillis等参数灵活调优一句话总结G1 把“不可控的大扫除”变成了“可计划的小范围整理”既保证了效率又稳住了停顿视频看了几百小时还迷糊关注我几分钟让你秒懂发点评论可以给博主加热度哦