JVM 中的垃圾回收算法及垃圾回收器详解

前言

Java 虚拟机(JVM)的自动内存管理机制中,垃圾回收(Garbage Collection, GC)是至关重要的一个环节。它不仅负责释放那些不再被使用的对象所占用的内存空间,还对程序的性能有着重要影响。本文将详细介绍 JVM 中的垃圾回收算法以及各个版本 JDK 对应的垃圾回收器,并探讨它们的工作原理和适用场景。


一、垃圾回收算法

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

标记-清除是最基础的垃圾回收算法之一。其工作过程分为两个阶段:

  • 标记阶段:遍历所有对象引用,找出哪些对象是存活的。
  • 清除阶段:回收未被标记的对象所占用的空间。

优点

  • 实现简单,不需要额外空间。

缺点

  • 效率低,特别是在存在大量对象的情况下。
  • 容易产生内存碎片,导致后续大对象分配时出现空间不足的问题。

2. 复制(Copying)

复制算法将可用内存按容量划分为两块,每次只使用其中一块。当这一块内存用完时,就将存活的对象复制到另一块上面,然后把已使用的内存空间一次清理掉。

优点

  • 不会产生内存碎片。
  • 实现简单,运行高效。

缺点

  • 内存利用率低,因为需要预留一半的内存用于复制。

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

标记-整理结合了标记-清除和复制的优点。在标记阶段之后,不是直接清除未标记的对象,而是让所有存活的对象向一端移动,然后清理掉端边界以外的内存。

优点

  • 解决了内存碎片问题。
  • 提高了内存利用率。

缺点

  • 移动对象的成本较高。

4. 分代收集(Generational Collection)

现代垃圾回收器通常采用分代收集的思想,根据对象存活周期的不同将其划分成不同的区域进行回收。一般分为年轻代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation,现已改为元空间 Metaspace)。年轻代又细分为 Eden 区和 Survivor 区(S0/S1)。

  • 年轻代:新创建的对象首先分配在这里,由于大部分对象生命周期较短,所以这里采用复制算法。
  • 老年代:经过几次垃圾回收后仍然存活的对象会被晋升到这里,采用标记-清除或标记-整理算法。
  • 元空间:存储类的元数据等信息,从 JDK8 开始,永久代被移除,改用本地内存实现的元空间替代。

二、垃圾回收器

随着 JDK 版本的发展,JVM 引入了多种垃圾回收器,每种都有其特定的应用场景和优化方向。

1. Serial 收集器

Serial 收集器是最基本的新生代垃圾收集器,单线程执行,适用于单核处理器或小型应用。

  • JDK 版本:自 JDK1.3 以来一直存在。
  • 特点:简单高效,适合于客户端模式下的应用。

2. Parallel/Throughput 收集器

Parallel 收集器也是一款针对新生代的收集器,但它可以使用多线程并行执行,提高了垃圾回收效率,适合于多核服务器环境。

  • JDK 版本:从 JDK6 开始成为默认的服务器端收集器。
  • 特点:追求高吞吐量,减少 GC 停顿时间。

3. CMS(Concurrent Mark Sweep)收集器

CMS 是一种以获取最短回收停顿时间为目标的老年代垃圾收集器,通过并发方式执行大部分工作,减少了应用程序的停顿时间。

  • JDK 版本:JDK5 引入,JDK9 中被标记为废弃。
  • 特点:低延迟,但可能会导致碎片化问题,且 CPU 资源消耗较大。

4. G1(Garbage First)收集器

G1 是面向服务端应用的垃圾收集器,旨在替代 CMS。它将堆划分为多个大小相等的独立区域(Region),跟踪每个 Region 里垃圾的数量,优先回收价值最大的 Region。

  • JDK 版本:JDK7u4 作为实验性功能推出,JDK9 成为默认收集器。
  • 特点:预测停顿时间模型,可配置最大停顿时间目标;减少了 Full GC 的发生频率。

5. ZGC(Z Garbage Collector)

ZGC 是一个可扩展的低延迟垃圾收集器,设计目标是在任意堆大小下都能提供不超过 10 毫秒的暂停时间。

  • JDK 版本:JDK11 作为实验特性引入,JDK15 正式发布。
  • 特点:非常低的停顿时间,支持非常大的堆(TB 级别)。

6. Shenandoah

Shenandoah 与 ZGC 类似,也是一个低暂停时间的垃圾收集器,但它是由 Red Hat 开发并贡献给 OpenJDK 项目的。

  • JDK 版本:JDK12 引入,JDK15 GA。
  • 特点:同样专注于降低 GC 停顿时间,具有更广泛的平台支持。

三、总结

选择合适的垃圾回收器对于提升应用性能至关重要。不同的应用场景可能需要不同类型的垃圾回收策略。例如,对于响应时间敏感的服务端应用,可能更适合使用 G1 或 ZGC;而对于后台批处理任务,则可能更倾向于使用 Parallel 收集器来最大化吞吐量。

随着 JDK 版本的不断演进,新的垃圾回收技术也在持续发展。开发者应密切关注这些变化,并根据实际需求调整自己的垃圾回收策略,以获得最佳的应用性能。希望这篇文章能帮助你更好地理解 JVM 中的垃圾回收机制及其背后的原理。如果你有任何疑问或者想要分享的经验,请在评论区留言!

相关推荐
Fency咖啡7 分钟前
Spring进阶 - SpringMVC实现原理(二)DispatcherServlet处理请求的过程
java·后端·spring·mvc
m0_6515939134 分钟前
位置透明性、Spring Cloud Gateway与reactor响应式编程的关系
java·spring cloud·系统架构·gateway
玉树临风江流儿1 小时前
Cmake使用CPack实现打包
java·服务器·前端
yunmi_1 小时前
微服务,Spring Cloud 和 Eureka:服务发现工具
java·spring boot·spring cloud·微服务·eureka·架构·服务发现
一叶飘零_sweeeet1 小时前
从 0 到 PB 级存储:MinIO 分布式文件系统实战指南与架构解密
java·架构·大文件存储
Dest1ny-安全1 小时前
Java代码审计-Servlet基础(1)
java·python·servlet
lingggggaaaa1 小时前
小迪安全v2023学习笔记(九十七天)—— 云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行
java·笔记·学习·安全·网络安全·云原生·kubernetes
Mr.Ja2 小时前
【LeetCode 热题 100】No.49—— 字母异位词分组(Java 版)
java·算法·leetcode·字母异位词分组
2401_841495642 小时前
【数据结构】链栈的基本操作
java·数据结构·c++·python·算法·链表·链栈
元亓亓亓2 小时前
SSM--day2--Spring(二)--核心容器&注解开发&Spring整合
java·后端·spring