面试题:Java 的 G1 垃圾回收流程是怎样的?

G1(Garbage-First)是 Java 中一种面向全堆的垃圾回收器,旨在实现低延迟和高吞吐量的垃圾回收。G1 将堆内存划分为多个大小相等的区域(Region),每个区域可以是 Eden、Survivor 或 Old 区。G1 的垃圾回收流程分为以下几个主要阶段:


1. 年轻代垃圾回收(Young GC)

年轻代垃圾回收是 G1 中最频繁的垃圾回收操作,主要回收 Eden 区和 Survivor 区中的对象。

流程

  1. 初始标记(Initial Mark)
    • 这是一个 STW(Stop-The-World)阶段,标记从 GC Roots 直接可达的对象。
    • 初始标记阶段通常会与年轻代垃圾回收一起执行,以减少额外的停顿时间。
  2. 根区域扫描(Root Region Scanning)
    • 扫描 Survivor 区中直接引用老年代对象的区域。
    • 这一阶段是并发的,不会暂停应用线程。
  3. 并发标记(Concurrent Marking)
    • 并发标记阶段会遍历整个堆,标记所有存活对象。
    • 这一阶段是并发的,应用线程可以继续运行。
  4. 最终标记(Final Marking)
    • 这是一个 STW 阶段,处理在并发标记期间遗漏的对象。
    • G1 使用 SATB(Snapshot-At-The-Beginning)算法,确保所有存活对象都被正确标记。
  5. 清理(Cleanup)
    • 清理阶段会统计每个区域的存活对象,并选择回收价值最高的区域进行回收。
    • 这一阶段是部分并发的,可能会产生浮动垃圾(Floating Garbage)。

2. 混合垃圾回收(Mixed GC)

混合垃圾回收是 G1 中用于回收老年代区域的垃圾回收操作。它会在年轻代垃圾回收之后执行,回收一部分老年代区域。

流程

  1. 初始标记(Initial Mark)
    • 与年轻代垃圾回收的初始标记阶段相同,标记从 GC Roots 直接可达的对象。
  2. 并发标记(Concurrent Marking)
    • 并发标记阶段会遍历整个堆,标记所有存活对象。
  3. 最终标记(Final Marking)
    • 处理在并发标记期间遗漏的对象,确保所有存活对象都被正确标记。
  4. 清理(Cleanup)
    • 统计每个区域的存活对象,并选择回收价值最高的区域进行回收。
  5. 复制/清除(Evacuation)
    • 将存活对象从被回收的区域复制到新的区域,并清空被回收的区域。

3. 全堆垃圾回收(Full GC)

全堆垃圾回收是 G1 中的一种备用机制,当 G1 无法在预期时间内完成垃圾回收时,会触发 Full GC。Full GC 是单线程的,会导致较长的停顿时间。

流程

  1. 标记(Marking)
    • 标记所有存活对象。
  2. 清除(Sweeping)
    • 清除所有未被标记的对象。
  3. 压缩(Compaction)
    • 压缩堆内存,减少内存碎片。

G1 垃圾回收流程的总结

阶段年轻代垃圾回收(Young GC)混合垃圾回收(Mixed GC)全堆垃圾回收(Full GC)
初始标记STW,标记 GC Roots 直接可达的对象STW,标记 GC Roots 直接可达的对象STW,标记所有存活对象
根区域扫描扫描 Survivor 区中引用老年代对象的区域
并发标记并发标记所有存活对象并发标记所有存活对象
最终标记STW,处理遗漏对象STW,处理遗漏对象
清理统计存活对象,选择回收区域统计存活对象,选择回收区域
复制/清除将存活对象复制到新区域将存活对象复制到新区域清除未标记对象,压缩堆内存

G1 垃圾回收的特点

  1. 低延迟:通过并发标记和部分并发清理,减少 STW 时间。
  2. 高吞吐量:通过分区域回收,提高垃圾回收的效率。
  3. 可预测的停顿时间:通过设置最大停顿时间目标(-XX:MaxGCPauseMillis ),控制垃圾回收的停顿时间。

总结

G1 垃圾回收器的流程包括年轻代垃圾回收、混合垃圾回收和全堆垃圾回收。通过并发标记、SATB 算法和分区域回收,G1 能够在低延迟和高吞吐量之间取得平衡,适用于大内存和多核处理器的应用场景。

THE END
点赞13 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容