JVM垃圾回收器及策略详解

JVM 垃圾回收器(Garbage Collector, GC)负责自动管理 Java 程序运行过程中产生的内存垃圾(不再被引用的对象),回收其占用的内存空间,防止内存泄漏并确保应用程序的稳定运行。不同的垃圾回收器采用了不同的算法和策略来平衡吞吐量(应用程序执行时间占总时间的比例)、停顿时间(Stop-The-World, STW - 暂停应用程序线程进行垃圾回收的时间)和内存占用

以下是主要的 JVM 垃圾回收器及其对应的核心垃圾回收策略(截至 Java 17):

一、经典分代收集器 (基于分代假说)

JVM 堆内存通常划分为年轻代 (Young Generation)老年代 (Old Generation/Tenured Generation)。大部分对象生命周期很短(朝生夕死),适合在年轻代快速回收;存活下来的对象会逐渐晋升到老年代,老年代的对象回收频率较低但回收成本较高。

  1. Serial GC (-XX:+UseSerialGC)

    • 策略: 单线程收集器。
    • 年轻代算法: 标记-复制 (Mark-Copy)。将 Eden 区和存活的一个 Survivor 区的对象复制到另一个空的 Survivor 区(或直接晋升到老年代),然后清空 Eden 和原来的 Survivor。
    • 老年代算法: 标记-整理 (Mark-Compact)。标记存活对象,然后将它们向内存空间的一端移动(整理),清理掉边界外的所有内存(即垃圾)。
    • 特点: 简单高效,没有线程交互开销。但进行垃圾回收时,会暂停所有应用线程 (STW)。适用于单核 CPU、客户端模式或对停顿时间不敏感的微服务/小型应用。
  2. Parallel GC / Throughput GC (-XX:+UseParallelGC)

    • 策略: 多线程并行收集器,目标是最大化吞吐量
    • 年轻代算法: 并行标记-复制 (Parallel Mark-Copy)。利用多线程并行执行年轻代的垃圾回收工作,加速复制过程。
    • 老年代算法: 并行标记-整理 (Parallel Mark-Compact)。同样利用多线程并行执行老年代的标记和整理工作。
    • 特点: 显著提升了垃圾回收速度(相比 Serial),减少了 STW 时间(在多核环境下)。是 JDK 8 及之前版本的默认垃圾回收器。适合后台运算、科学计算等对吞吐量要求高、能容忍中等停顿时间(可能几百毫秒)的应用。
  3. ParNew GC (-XX:+UseParNewGC)

    • 策略: Serial GC 的多线程版本,专门用于年轻代。需要与 CMS 搭配使用。
    • 年轻代算法: 并行标记-复制 (Parallel Mark-Copy)。原理同 Parallel GC 的年轻代。
    • 老年代搭档: 必须配合 CMS 使用。
    • 特点: 在年轻代回收上比 Serial 更快(多核)。主要用于作为 CMS 的年轻代搭档。在 JDK 9 后被标记为废弃,因为 G1 成为默认且 CMS 本身也被废弃。
  4. CMS (Concurrent Mark-Sweep) GC (-XX:+UseConcMarkSweepGC - JDK 14 被移除)

    • 策略: 以获取最短停顿时间为目标的收集器,特别是针对老年代。其核心是并发标记和清除,尽可能减少 STW 时间。
    • 年轻代算法: 通常搭配 ParNew (并行标记-复制)。
    • 老年代算法: 并发标记-清除 (Concurrent Mark-Sweep)。过程复杂:
      1. 初始标记 (Initial Mark - STW): 标记 GC Roots 直接关联的对象,速度快。
      2. 并发标记 (Concurrent Mark): GC 线程与应用线程并发执行,遍历对象图进行可达性分析。
      3. 重新标记 (Remark - STW): 修正并发标记期间因应用线程运行导致标记变动的部分。比初始标记长,但远短于并发标记。
      4. 并发清除 (Concurrent Sweep): GC 线程与应用线程并发执行,清除未被标记(即垃圾)的对象。
    • 特点:
      • 老年代回收的大部分工作(标记和清除)与应用线程并发执行,显著减少了老年代回收的 STW 时间
      • 采用标记-清除 (Mark-Sweep),会产生内存碎片。当碎片过多导致无法分配大对象时,会触发一次 Serial Old GC(单线程的标记-整理)进行碎片整理,此时停顿时间会很长。
      • 对 CPU 资源敏感,并发阶段会占用一部分 CPU 资源,可能影响应用吞吐量。
      • 无法处理浮动垃圾 (Floating Garbage):在并发清除阶段应用线程产生的垃圾,只能留到下一次 GC 处理。
      • JDK 9 被标记为废弃,JDK 14 中被移除。主要被 G1 和 ZGC/Shenandoah 取代。

二、新一代垃圾回收器 (面向低延迟)

  1. G1 (Garbage-First) GC (-XX:+UseG1GC - JDK 9+ 默认)

    • 策略: 面向服务端应用兼顾吞吐量和低停顿时间。核心思想是将堆划分为多个大小相等的 Region,每个 Region 可以是 Eden, Survivor, Old 或 Humongous(存放大对象)区。
    • 算法: 标记-整理 (Mark-Compact) 为主,但在局部 Region 之间采用复制 (Copy) 算法。
    • 回收过程 (Mixed GC):
      • 年轻代回收 (Young GC - STW): 对 Eden 和 Survivor Region 进行回收(标记-复制),存活对象复制到新的 Survivor Region 或晋升到 Old Region。
      • 并发标记周期 (Concurrent Cycle): 类似 CMS,但不分代全局标记。
        1. 初始标记 (STW - 依附于 Young GC)。
        2. 根区域扫描。
        3. 并发标记。
        4. 最终标记 (STW)。
        5. 清理 (STW + 并发):统计各 Region 的存活对象和回收价值(Garbage-First 名字来源),选择回收价值高的 Region 放入 Collection Set。
      • 混合回收 (Mixed GC - STW): 对 Collection Set 中的 Region(包含年轻代和老年代 Region)进行回收,采用复制算法将存活对象复制到空闲 Region(相当于整理)。
      • Full GC (Serial Full GC - 后备): 当回收速度跟不上对象分配速度或无法找到足够连续空间时触发,退化使用 Serial Old GC 进行整个堆的标记-整理(应尽量避免)。
    • 特点:
      • 可预测的停顿时间模型 (-XX:MaxGCPauseMillis):通过控制每次回收的 Region 数量来大致控制停顿时间。
      • 并行与并发结合:充分利用多核优势,部分工作与应用线程并发执行。
      • 分 Region 管理:按 Region 回收,优先回收价值高的 Region(垃圾最多)。
      • 整体标记-整理,局部复制:有效避免了 CMS 的内存碎片问题。
      • JDK 9 及以后版本的默认垃圾回收器,适用性非常广。
  2. ZGC (Z Garbage Collector) (-XX:+UseZGC)

    • 策略: 超低延迟 垃圾回收器,目标是将 STW 停顿时间控制在 10ms 以内,且与堆大小无关(TB 级堆也能保持低停顿)。适用于对延迟极其敏感的应用。
    • 核心技术:
      • 染色指针 (Colored Pointers): 在指针中嵌入元数据(标记位、重映射标记位等),替代传统的内存对象头存储标记信息。
      • 读屏障 (Load Barrier): 在应用线程从堆中加载引用时触发一小段代码,配合染色指针实现并发处理(如标记、重定位)。
    • 算法: 基于 Region 的并发标记-整理。
    • 回收阶段 (几乎全并发):
      1. 并发标记 (Concurrent Mark): 遍历对象图标记可达对象。
      2. 并发预备重分配 (Concurrent Prepare for Relocation): 确定需要清理(重定位)的 Region。
      3. 并发重分配 (Concurrent Relocation): 核心阶段。将存活对象复制到新的 Region,并通过读屏障和应用线程协作逐步更新所有指向这些对象的引用(自愈指针)。
      4. 并发重映射/标记 (Concurrent Remap/Remark): 修正重分配期间漏掉的引用(较少发生)。
    • 特点:
      • 超低停顿时间 (Sub-millisecond to ~10ms):STW 阶段仅剩初始标记和最终标记中的根扫描部分(极短)。
      • 高吞吐量损失相对小:虽然并发操作消耗资源,但设计优秀,吞吐量损失比 CMS 小。
      • 大堆友好:停顿时间不随堆大小增长而增加。
      • 支持压缩/整理:消除碎片。
      • JDK 15 正式发布生产可用,仍在快速发展中。
  3. Shenandoah GC (-XX:+UseShenandoahGC)

    • 策略: 与 ZGC 目标类似,追求低停顿时间(通常 <10ms) 且与堆大小无关。
    • 核心技术与 ZGC 异同:
      • 转发指针 (Brooks Pointer / Forwarding Pointer): 在每个对象头中增加一个额外的“转发指针”字段。在对象被复制后,旧位置的转发指针指向新位置。
      • 读屏障 (Load Barrier) 和 写屏障 (Write Barrier): 都需要。读屏障用于解决并发引用加载问题(类似ZGC),写屏障用于捕获引用更新(确保在并发移动时引用的正确性)。
    • 算法: 基于 Region 的并发标记-复制/整理。
    • 回收阶段 (几乎全并发):
      1. 初始标记 (Initial Mark - STW):标记根。
      2. 并发标记 (Concurrent Mark)
      3. 最终标记 (Final Mark - STW):处理剩余的 SATB(Snapshot-At-The-Beginning)引用。
      4. 并发清理 (Concurrent Cleanup):清理无存活对象的 Region。
      5. 并发回收 (Concurrent Evacuation): 核心差异点。并发地将存活对象复制到新的 Region。应用线程在访问对象时,通过读/写屏障感知并处理对象移动和引用更新。
      6. 初始引用更新 (Init Update Refs - STW):短暂暂停确保所有线程看到回收开始前的状态。
      7. 并发引用更新 (Concurrent Update References): 遍历堆,更新指向已移动对象的引用。
      8. 最终引用更新 + 清理 (Final Update Refs + Cleanup - STW):完成引用更新并清理。
    • 特点:
      • 超低停顿时间:目标与 ZGC 一致。
      • 与 ZGC 性能接近:两者在低延迟方面表现都非常出色,具体选择可能取决于具体应用场景、JVM 版本和平台优化。
      • 更早进入 OpenJDK (JDK 12),但最初由 Red Hat 主导。现已是 OpenJDK 主流 GC 之一。

总结对比表

垃圾回收器目标年轻代算法老年代算法线程模式主要特点/适用场景STW 时间碎片JDK 状态
Serial单核简单标记-复制 (单)标记-整理 (单)单线程 STW客户端模式, 资源受限可用
Parallel/Throughput高吞吐量标记-复制 (并)标记-整理 (并)多线程并行 STW后台计算, 批处理, JDK8 默认中等可用, JDK8 默认
ParNew配合CMS年轻代标记-复制 (并)需搭配 CMS多线程并行 STWCMS 的年轻代搭档年轻代短-废弃 (JDK9+)
CMS低停顿 (老年代)(通常 ParNew)并发标记-清除并发+并行老年代低停顿, Web应用 (历史), 内存碎片, CPU敏感老年代短 (除碎片整理)移除 (JDK14+)
G1吞吐量+可控停顿复制 (Region)标记-整理+复制 (Region)并发+并行通用服务端, JDK9+ 默认, 可预测停顿, Region, Mixed GC可控 (可设置)极少JDK9+ 默认
ZGC超低停顿无分代 (Region)并发标记-整理 (染色指针)并发为主极低延迟 (10ms), 大堆, 染色指针, 读屏障极短 (亚毫秒)生产可用 (JDK15+)
Shenandoah超低停顿无分代 (Region)并发标记-复制/整理 (转发指针)并发为主极低延迟 (10ms), 大堆, 转发指针, 读/写屏障极短生产可用 (JDK12+)

选择建议

  1. 吞吐量优先 (CPU 密集型): Parallel GC (或 G1 调优后)。
  2. 中等延迟要求 (通用服务端): G1 GC (JDK9+ 默认,平衡性最好)。
  3. 极低延迟要求 (延迟敏感型应用,如金融交易、实时系统): ZGCShenandoah GC
  4. 小内存/客户端/嵌入式: Serial GC
  5. 避免使用: CMS (已移除),ParNew (废弃)。

重要参数

  • -XX:+Use<GCName>GC: 启用特定 GC (e.g., -XX:+UseG1GC, -XX:+UseZGC)。
  • -Xms / -Xmx: 设置堆的初始大小和最大大小。
  • -XX:NewRatio: 年轻代与老年代的比例 (e.g., 2 表示 老年代:年轻代=2:1)。
  • -XX:SurvivorRatio: Eden 区与一个 Survivor 区的比例 (e.g., 8 表示 Eden:S0:S1=8:1:1)。
  • G1:
    • -XX:MaxGCPauseMillis: 期望的最大 GC 停顿时间目标 (毫秒, 默认 200ms)。
    • -XX:G1HeapRegionSize: 设置 Region 大小 (1MB-32MB, 2的幂)。
  • ZGC/Shenandoah: 通常自动调优,也可设置堆大小等基础参数。

理解不同垃圾回收器的原理和适用场景,结合应用的具体需求(延迟、吞吐量、堆大小)进行选择和调优,是保证 Java 应用性能稳定的关键环节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走过冬季

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值