G1
G1垃圾回收的过程
如何实现maxPauseTime
G1的特点, 优点和缺点
G1 是 Java HotSpot 虚拟机自 JDK7u4 起提供的服务器端垃圾回收器,目标是替代 CMS,适用于大堆内存、低延迟场景。G1 通过分区、并发和自适应等机制,实现高吞吐量和可预测的停顿时间。
G1 的主要特点
- 分区管理(Region):将堆划分为多个大小相等的 Region,每个 Region 可作为 Eden、Survivor 或 Old 区,灵活管理内存。
- 分代收集:同时支持年轻代和老年代的垃圾收集。
- 可预测停顿时间:允许用户设置最大停顿时间目标(如
-XX:MaxGCPauseMillis),G1 会自适应调整回收行为以尽量满足目标。 - 并发与并行:支持多线程并发标记和回收,减少 Stop-The-World(STW)时间。
- 垃圾优先:优先回收垃圾最多的 Region,提高回收效率。
- 整体堆回收:可对整个堆进行回收,避免碎片化。
G1 垃圾回收过程
触发条件
- 年轻代空间不足时触发 Young GC。
- 老年代空间不足或达到阈值时触发 Mixed GC 或 Full GC。
- 显式调用
System.gc()可能触发 Full GC。
回收阶段
G1 的回收阶段分为两类:Young Only GC 和 Mixed GC。
Young Only GC 阶段
- 仅回收年轻代(Eden 和 Survivor 区)的 Region。
- 触发条件:年轻代空间不足。
- 过程:采用并行回收,通常伴随初始标记(Initial Mark),会发生短暂的 STW(Stop-The-World)暂停。
- 目标:快速回收短生命周期对象,腾出新生代空间。
Young Only GC 的过程
Young Only GC 主要针对年轻代(Eden 和 Survivor 区)的 Region 进行回收,流程如下:
触发条件
当年轻代空间不足时(如 Eden 区分配失败),会触发 Young Only GC。初始标记(Initial Mark)
该阶段会标记从 GC Roots 可达的对象,通常与 Young GC 一起发生,并伴随一次短暂的 Stop-The-World(STW)暂停。并行回收
多个 GC 线程并行回收年轻代的 Region,将存活对象复制到 Survivor 区或晋升到老年代。释放空间
回收后,Eden 区和部分 Survivor 区被清空,为新对象分配腾出空间。目标
快速回收短生命周期对象,减少新生代内存压力,提高分配效率。
Young Only GC 不会回收老年代的 Region,主要目的是高效管理新生代对象,减少应用停顿时间。
Mixed GC 阶段
- 同时回收年轻代和部分老年代的 Region。
- 触发条件:老年代空间达到阈值或并发标记完成后。
- 过程:在多次 Mixed GC 中,优先选择垃圾比例高的老年代 Region 与年轻代一起回收,减少老年代垃圾堆积。
- 目标:逐步清理老年代,避免 Full GC,提升整体堆利用率。
Mixed GC 的过程
Mixed GC 主要同时回收年轻代(Eden 和 Survivor 区)以及部分老年代的 Region,流程如下:
触发条件
当老年代空间达到一定阈值,或并发标记和最终标记(Remark)阶段完成后,会触发 Mixed GC。筛选回收 Region
G1 根据并发标记结果,选择垃圾比例高的老年代 Region,与年轻代 Region 一起加入本次回收。STW 暂停
Mixed GC 过程中会有多次短暂的 Stop-The-World(STW)暂停,用于对象标记和回收。并行回收
多个 GC 线程并行回收被选中的年轻代和老年代 Region,将存活对象复制到 Survivor 区或晋升到老年代。多轮执行
Mixed GC 通常不会一次性回收所有老年代垃圾 Region,而是分多轮进行,每轮优先回收垃圾比例最高的 Region,逐步清理老年代。目标
逐步减少老年代的垃圾对象,避免 Full GC 的发生,提高堆空间利用率,保证应用的低延迟和高吞吐。
Mixed GC 是 G1 的核心创新之一,通过分阶段、分批次地回收老年代,提升了大堆场景下的垃圾回收效率和可预测性。
G1 会根据堆的使用情况和停顿目标,动态决定执行 Young Only GC 还是 Mixed GC,从而实现高效且可预测的垃圾回收。
G1 的原理
- Region 划分:堆被划分为 2048 个左右的 Region,每个 Region 大小可配置(1MB~32MB)。
- Remembered Set:每个 Region 维护一个 Remembered Set,记录其他 Region 指向本 Region 的引用,支持跨 Region 并发回收。
- SATB 算法:并发标记阶段采用快照算法,保证标记准确性。
- 自适应回收:根据停顿时间目标和 Region 垃圾比例,动态选择回收哪些 Region。
G1 如何自适应 GC
- 用户可通过
-XX:MaxGCPauseMillis设置期望的最大 GC 停顿时间。 - G1 会根据应用分配速率、存活对象比例、Region 垃圾量等,动态调整每次回收的 Region 数量和类型,尽量满足停顿目标。
如何使用 G1
- 启用参数:
-XX:+UseG1GC - 设置堆大小:
-Xms、-Xmx - 设置停顿目标:
-XX:MaxGCPauseMillis=200(单位毫秒) - 其他常用参数:
-XX:InitiatingHeapOccupancyPercent:触发并发标记的堆占用百分比(默认 45)-XX:G1HeapRegionSize:Region 大小-XX:ParallelGCThreads:GC 并行线程数
常见问题排查
OOM(内存溢出)
- 检查堆大小、Region 配置、对象分配速率。
- 分析 GC 日志,定位内存泄漏或大对象分配。
内存泄漏
- 使用 MAT、VisualVM 等工具分析堆转储文件。
- 检查长生命周期对象引用。
Full GC 频繁
- 堆空间不足或碎片化严重。
- 老年代回收不及时,调整参数或优化代码。
G1 三色标记法
G1 垃圾回收器在并发标记阶段采用三色标记法(Tri-color Marking),用于高效、准确地识别存活对象。三色标记法将对象分为三类:
- 白色:未被访问过的对象,初始时所有对象都是白色。如果标记阶段结束后仍为白色,则认为是垃圾对象,可以回收。
- 灰色:已被访问但其引用的对象还未全部扫描的对象。灰色对象需要进一步处理。
- 黑色:自身已被访问且其引用的对象也都已扫描完毕的对象,表示存活对象。
标记过程
初始阶段
所有对象为白色。GC Roots 直接引用的对象被标记为灰色,加入待处理队列。标记推进
不断从灰色队列中取出对象,将其引用的白色对象标记为灰色,并将自身标记为黑色。如此循环,直到没有灰色对象。标记结束
剩下的白色对象即为不可达对象,可以被回收。
SATB(Snapshot-At-The-Beginning)算法
G1 在并发标记时采用 SATB 算法,确保在标记过程中对象引用的变化不会导致“漏标”或“误标”。SATB 通过记录并发标记开始时的对象引用快照,保证标记准确性。
优势
- 能高效并发地标记存活对象,减少 STW 停顿时间。
- 与 Remembered Set 配合,支持跨 Region 的引用追踪。
三色标记法是 G1 并发标记阶段的核心机制,保证了大堆场景下的高效和准确的垃圾回收。
除了三色标记法,垃圾回收器还有其他常见的对象可达性分析和标记方法,主要包括:
引用计数法(Reference Counting) 每个对象维护一个引用计数,引用增加时计数加一,引用断开时计数减一,计数为零时对象可回收。 优点:实现简单,实时回收。 缺点:无法处理循环引用,现代主流 JVM 不采用。 根可达性分析(Root Set/Tracing GC) 从 GC Roots(如栈、静态变量、JNI 引用等)出发,遍历对象图,所有可达对象为存活对象。三色标记法其实是根可达性分析的并发优化实现。
分代收集(Generational Collection) 根据对象生命周期将堆划分为新生代和老年代,分别采用不同的回收策略(如复制算法、标记-清除、标记-整理等)。
标记-清除(Mark-Sweep) 先遍历对象图标记所有存活对象,然后清除未被标记的对象。
标记-整理(Mark-Compact) 标记存活对象后,将其移动到内存一端,整理内存碎片。
复制算法(Copying) 将存活对象从一块内存复制到另一块,回收整个原内存区域,常用于新生代。
Remembered Set
**Remembered Set(记忆集)**是 G1 垃圾回收器中用于支持跨 Region 引用追踪的重要数据结构。
在 G1 中,堆被划分为多个 Region。每个 Region 都维护一个自己的 Remembered Set,用于记录其他 Region 中的对象对本 Region 内对象的引用。这样,在进行并发和增量回收时,G1 不需要全堆扫描所有引用关系,只需关注相关的 Remembered Set,大大提升了回收效率。
作用
- 支持跨 Region 的引用追踪,保证垃圾回收时不会遗漏存活对象。
- 降低 GC 扫描范围,提升并发回收性能。
- 与写屏障(Write Barrier)配合,实时更新引用关系。
工作原理
- 当某个 Region 外的对象引用了本 Region 的对象时,通过写屏障机制将该引用关系记录到本 Region 的 Remembered Set 中。
- 在回收本 Region 时,只需扫描其 Remembered Set,找到所有可能引用本 Region 的外部对象,确保标记完整性。
Remembered Set 是 G1 实现高效、可扩展垃圾回收的关键机制之一,尤其适用于大堆和高并发场景