JVM垃圾回收器

JVM 的垃圾回收机制主要通过不同的垃圾收集器来实现,垃圾收集器的设计围绕着几个核心目标:吞吐量、延迟(停顿时间)、内存占用,并根据它们工作的内存区域(年轻代/老年代) 和工作方式(串行/并行/并发) 进行分类。

以下是 JVM 中主要的垃圾收集器类型及其特点,通常从两个维度来理解:

维度一:按工作区域(分代收集的核心思想)

  1. 年轻代收集器: 主要负责回收年轻代(Young Generation)中的对象。

    • 特点: 年轻代对象的特点是“朝生夕死”,回收频率高,速度快。通常使用复制算法

    • 常见收集器:

      • Serial:单线程,复制算法。

      • ParNewSerial 的多线程并行版本,复制算法。

      • Parallel Scavenge:多线程并行,复制算法,关注吞吐量(用户代码运行时间 / (用户代码运行时间 + GC时间))。

  2. 老年代收集器: 主要负责回收老年代(Old Generation)中的对象。

    • 特点: 老年代对象存活率高,回收频率相对较低,但每次回收耗时可能较长。通常使用标记-清除算法标记-整理算法

    • 常见收集器:

      • Serial Old:单线程,标记-整理算法(常作为 Serial 的老年代搭档)。

      • Parallel Old:多线程并行,标记-整理算法(Parallel Scavenge 的老年代搭档,关注吞吐量)。

      • CMS:多线程并发,以标记-清除为主,关注低延迟(减少停顿时间)。(注:JDK 9 开始标记废弃,JDK 14 中移除)

  3. 整堆收集器: 不再严格区分年轻代和老年代物理区域,将整个堆视为一个或多个逻辑区域(Region)进行管理。

    • 特点: 可以更灵活地分配和回收内存,目标是在可控的停顿时间内处理超大堆

    • 常见收集器:

      • G1:将堆划分为多个大小相等的 Region,基于 Region 进行回收,使用标记-整理算法,可预测停顿时间模型。 (JDK 9 起成为默认收集器)。

      • ZGC:使用染色指针和读屏障技术,几乎所有阶段都是并发的(STW 时间极短,通常 < 1ms),处理超大堆(TB 级别)能力优秀。关注极低延迟

      • Shenandoah:与 ZGC 类似,也追求极低停顿时间,使用了不同的技术(如 Brooks 指针、读屏障与写屏障结合)。关注极低延迟

维度二:按线程工作方式

  1. 串行收集器:

    • 使用单个线程进行垃圾回收工作。

    • 特点: 简单高效,没有线程交互开销。但在多核环境下,GC 时会完全暂停所有应用线程(Stop-The-World, STW),导致较长的停顿时间。

    • 代表: Serial (Young), Serial Old (Old)。

  2. 并行收集器:

    • 使用多个线程并行地进行垃圾回收工作。

    • 特点: 在多核 CPU 上能显著缩短 STW 停顿时间,提高吞吐量。但 GC 时仍然会暂停所有应用线程。

    • 代表: ParNew (Young), Parallel Scavenge (Young), Parallel Old (Old)。

  3. 并发收集器:

    • 垃圾回收的某些阶段(尤其是耗时长的标记阶段)与应用线程并发执行

    • 特点: 大大减少了 STW 停顿时间,追求低延迟。但会因为并发执行带来额外的 CPU 和内存开销(如写屏障),可能略微降低应用吞吐量。实现更复杂。

    • 代表 

      • CMS:并发标记和并发清除(老年代)
      • G1:并发标记(整个堆)
      • ZGC:几乎所有阶段(标记、转移、重定位)都是并发的
      • Shenandoah:并发标记、并发转移

总结主要的垃圾收集器类型:

  1. Serial:单线程STW垃圾回收器,工作在年轻代。采用拷贝算法
  2. Serial Old:单线程STW垃圾回收器,工作在老年代。采用标记清除加压缩算法
  3. Parallel Scavenge:并行垃圾回收,工作在年轻代。采用拷贝算法
  4. Parallel Old:并行垃圾回收,工作在老年代。采用标记清除加压缩算法
  5. ParNew:并行垃圾回收,工作在年轻代。专门配合CMS使用
  6. CMS(Concurrent Mark-Sweep):并发标记清除,工作在老年代,采用标记清除算法
  7. G1(Garbage First):垃圾优先算法,采用拷贝算法
  8. ZGC(Z Garbage Collector):一种可伸缩的低延迟垃圾回收器,旨在处理TB级别的堆,同时保持低毫秒级别的停顿时间。它通过使用读屏障和染色指针来实现这一点,并且在垃圾回收过程中几乎不需要暂停应用线程
  9. Shenandoah GC:是一种旨在实现低停顿时间的垃圾回收器,它通过并发的方式来回收内存。Shenandoah的目标是减少停顿时间,而不是优化吞吐量,适用于需要大内存和低延迟的应用

关键点:

  • 没有单一“最好”的收集器: 选择取决于应用需求(吞吐量 vs 延迟 vs 内存)、堆大小、可用 CPU 资源等。

  • 组合使用: 分代收集器通常是年轻代和老年代收集器配对使用(如 ParNew + CMSParallel Scavenge + Parallel Old)。

  • 发展趋势: 现代 JVM 更倾向于使用像 G1ZGCShenandoah 这样的整堆、低延迟收集器,它们能更好地处理大内存和低延迟需求的应用。

  • JDK 默认: JDK 8 默认 Parallel Scavenge + Parallel Old (吞吐量优先);JDK 9 到 JDK 20 默认 G1;JDK 21 起默认 ZGC(当满足条件时,否则回退到 G1

JVM 垃圾回收算法

在JVM(Java虚拟机)中,垃圾回收(GC,Garbage Collection)是自动管理内存的一个重要机制,它确保不再被程序使用的对象所占用的内存被释放。JVM的垃圾回收机制主要通过以下三大算法来实现:

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

  • 步骤
    • 清除:扫描堆,回收未标记的对象内存。
    • 标记:遍历对象图,标记所有存活对象。

  • 缺点:内存碎片化、效率较低(需全堆扫描)。
  • 适用收集器
    • CMS(老年代):主要使用标记-清除,避免整理停顿(但最终仍需碎片整理)。

2. 标记-整理 (Mark-Compact)

  • 步骤

    • 标记:同标记-清除。
    • 整理:将存活对象向内存一端移动,消除碎片。
  • 优点:解决碎片问题。
  • 缺点:移动对象需STW(Stop-The-World),延迟较高

  • 适用收集器
    • Serial Old:老年代默认算法
    • Parallel Old:老年代算法(配合Parallel Scavenge)
    • G1(老年代Region):回收阶段对部分Region进行整理
    • ZGC & Shenandoah:在并发转移阶段完成整理(通过指针转发技术)

3. 复制算法 (Copying)

  • 步骤
    • 复制完成后,清空 From 区并交换 From/To 角色。

    • 将内存分为两块(From、To),存活对象从 From 复制到 To。

  • 优点:无碎片、效率高(只扫描存活对象)

  • 缺点:浪费50%内存空间

  • 适用收集器仅年轻代):

    • Serial:单线程复制

    • ParNew:多线程并行复制

    • Parallel Scavenge:多线程并行复制(关注吞吐量)

    • G1(年轻代Region):将存活对象复制到Survivor或Old Region​​​

4. 分代收集 (Generational Collection)

  • 核心思想:根据对象生命周期划分区域(年轻代、老年代),对不同区域使用不同算法。
  • 组合方式:​​​​​​​
    • 老年代:标记-清除或标记-整理(处理长生命周期对象)。

    • 年轻代:复制算法(高效回收短命对象)。

  • ​​​​​​​​适用收集器
    • Serial + Serial Old
    • ParNew + CMS
    • Parallel Scavenge + Parallel Old

JVM 提供了多种具有不同工作方式和目标的垃圾收集器实现,开发者可以根据应用的具体需求进行选择和JVM调优

你可能感兴趣的:(JVM,java,jvm,jvm调优)