# Java 中有哪些垃圾回收算法?

7 min read
Table of Contents

Java 中有哪些垃圾回收算法?

Java 垃圾回收算法详解

【核心定义】

Java 垃圾回收算法是 JVM 自动管理内存的核心机制,通过识别并回收不再被引用的对象来释放堆内存空间,防止内存泄漏。

【关键要点】

  1. 标记-清除算法(Mark-Sweep)

    • 结论:最基础的垃圾回收算法,分为“标记”和“清除”两个阶段。
    • 原理:首先标记所有从 GC Roots 可达的存活对象,然后清除未被标记的死亡对象。会产生内存碎片。
  2. 复制算法(Copying)

    • 结论:将内存分为两块,每次只使用一块,存活对象复制到另一块。
    • 原理:适用于对象存活率低的场景(如新生代)。没有碎片问题,但内存利用率只有 50%。
  3. 标记-整理算法(Mark-Compact)

    • 结论:标记存活对象后,将所有存活对象向一端移动,然后清理边界外的内存。
    • 原理:解决了内存碎片问题,适合老年代回收,但移动对象成本较高。
  4. 分代收集算法(Generational Collection)

    • 结论:现代 JVM 的主流算法,基于对象生命周期特性采用不同策略。
    • 原理:将堆分为新生代(Young Generation)和老年代(Old Generation),新生代使用复制算法(Eden + Survivor),老年代使用标记-清除或标记-整理。

【深度推导/细节】

分代收集的合理性推导

核心矛盾:大多数对象“朝生夕死”(弱分代假说),少数对象长期存活。

逻辑拆解:

  • Step 1:统计表明 98% 的 Java 对象存活时间极短
  • Step 2:将堆分为新生代(占 1/3)和老年代(占 2/3)
  • Step 3:新生代采用复制算法(Eden:Survivor = 8:1:1 )
    • 新对象分配在 Eden 区
    • Minor GC 时,Eden 存活对象复制到 Survivor0
    • 再次 Minor GC,Eden 和 Survivor0 存活对象复制到 Survivor1
    • 对象年龄计数器达到阈值(默认 15)晋升到老年代
  • Step 4:老年代采用标记-整理/清除算法
    • 当老年代空间不足时触发 Full GC
    • Full GC 会 Stop The World,影响性能

关键数字解析

  • 新生代比例 8:1:1 :基于对象死亡率统计的优化,90% 空间给新对象,10% 给存活对象复制
  • 晋升年龄 15:对象头中年龄占 4 位,最大值为 15,是空间与精度的平衡
  • 大对象直接进入老年代:避免在新生代频繁复制大对象(-XX:PretenureSizeThreshold )

【关联/对比】

不同垃圾收集器实现对比

收集器算法特点适用场景线程关系
Serial单线程标记-复制/整理客户端模式Stop The World
Parallel Scavenge多线程复制/整理吞吐量优先并行收集
CMS并发标记-清除低延迟并发收集
G1分Region标记-整理平衡型并发+并行
ZGC染色指针并发整理超低延迟全并发

CMS vs G1 核心差异

  • CMS:基于标记-清除,会产生碎片,需要 Full GC 整理
  • G1:将堆划分为多个 Region,优先回收价值最高的 Region,可预测停顿时间

【线程安全与版本差异】

线程安全机制

  • Stop The World:所有应用线程暂停,确保对象引用关系不变
  • 安全点/安全区域:线程只能在特定位置暂停进行 GC
  • 写屏障:维护卡表(Card Table),记录老年代到新生代的引用

版本演进

  • Java 7/8:Parallel Scavenge + Parallel Old 为默认,CMS 作为低延迟选项
  • Java 9+:G1 成为默认收集器
  • Java 11:引入 ZGC(实验性),暂停时间 < 10ms
  • Java 17:ZGC 和 Shenandoah 成为生产就绪

『面试官追问』

高频追问问题:

  1. 为什么新生代要用复制算法?

    • 对象死亡率高,复制成本低
    • 避免内存碎片,提高分配效率(指针碰撞)
  2. G1 如何实现可预测的停顿时间?

    • 维护 Region 的回收价值(回收空间/时间)
    • 每个 GC 周期只回收部分 Region
    • 通过 -XX:MaxGCPauseMillis 参数控制
  3. 三色标记法如何解决“对象消失”问题?

    • 增量更新(CMS):记录新增的引用
    • 原始快照(G1):记录删除的引用
    • 通过写屏障实现
  4. ZGC 的染色指针原理?

    • 在 64 位指针中借用 4 位作为标记位
    • 无需对象头标记,并发效率更高
    • 支持 TB 级堆内存

性能调优关键参数:

  • -Xms/-Xmx:堆初始/最大大小
  • -XX:NewRatio :新生代/老年代比例
  • -XX:SurvivorRatio :Eden/Survivor 比例
  • -XX:MaxTenuringThreshold :晋升年龄阈值
  • -XX:+UseG1GC:启用 G1 收集器

总结:Java 垃圾回收算法从基础算法演进到分代收集,再发展到现在的 Region 分区和全并发收集。选择合适算法需权衡吞吐量、延迟和内存开销,理解底层原理是性能调优的基础。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

Comments