Java 的垃圾回收器(Garbage Collector, GC)是 JVM 的核心功能之一,负责自动管理内存,回收不再被引用的对象,释放内存空间以供新对象使用。以下是 Java 中垃圾回收器的详解,包括其工作原理、不同垃圾回收器的特点以及使用场景。
1. 垃圾回收的工作原理
1.1 垃圾回收的目标
- 自动回收堆内存中不再使用的对象。
- 提高程序运行效率,减少手动管理内存的风险(如内存泄漏、内存溢出)。
1.2 垃圾回收的判定条件
- 引用计数法(已废弃):对象被引用的次数为 0 时被认为是垃圾。
- 可达性分析法(现代 GC 使用):通过一组“GC Roots”对象,从根节点开始分析是否可以到达某个对象,无法到达的对象被视为垃圾。
GC Roots 的来源
- 当前栈帧中的局部变量。
- 方法区中的静态变量。
- 活跃的线程。
- JNI(Java Native Interface)引用的对象。
2. JVM 垃圾回收区域
垃圾回收器主要针对 堆内存,分为以下两大区域:
2.1 年轻代(Young Generation)
- Eden 区:对象首次分配内存的位置。
- Survivor 区:
- From Survivor 和 To Survivor,用于存放从 Eden 区复制的幸存对象。
- 多次复制后,幸存对象晋升到老年代。
特点:
- 对象生命周期短,回收频繁。
- 使用“Minor GC”(小型垃圾回收)。
2.2 老年代(Old Generation)
- 存储生命周期较长的对象(从年轻代晋升)。
- 发生“Major GC”或“Full GC”时才会清理。
3. 常见垃圾回收器
3.1 串行垃圾回收器(Serial GC)
- 特点:
- 单线程工作。
- 停止所有用户线程(Stop-The-World, STW)进行垃圾回收。
- 简单高效,适用于单线程环境。
- 参数:
-XX:+UseSerialGC
- 适用场景:
- 单核 CPU 或内存较小的场景。
- 桌面应用或开发测试环境。
3.2 并行垃圾回收器(Parallel GC)
- 特点:
- 多线程并行进行垃圾回收。
- 目标是最大化吞吐量(应用运行时间与垃圾回收时间的比值)。
- 适合高吞吐量场景。
- 参数:
-XX:+UseParallelGC
- 适用场景:
- 后台计算任务或批处理系统,要求高吞吐量而非低延迟。
3.3 CMS(Concurrent Mark-Sweep)垃圾回收器
- 特点:
- 以最小化 STW 为目标,适合低延迟场景。
- 采用“标记-清除”算法:
- 初始标记:标记 GC Roots 可达的对象(STW)。
- 并发标记:遍历整个堆,标记所有可达对象。
- 重新标记:处理并发标记期间的变化(STW)。
- 并发清除:回收不可达对象。
- 参数:
-XX:+UseConcMarkSweepGC
- 优点:
- 减少停顿时间。
- 缺点:
- 内存碎片化问题。
- 并发阶段对 CPU 消耗较高。
- 适用场景:
- 需要低延迟的响应式应用,例如 Web 服务。
3.4 G1(Garbage-First)垃圾回收器
- 特点:
- 目标是低延迟和高吞吐量的平衡。
- 将堆划分为多个固定大小的区域(Region),每次回收优先处理垃圾最多的区域。
- 支持预测停顿时间。
- 参数:
-XX:+UseG1GC
- 运行过程:
- 初始标记:标记 GC Roots 可达对象(STW)。
- 并发标记:并发标记整个堆。
- 最终标记:修正并发标记期间的变化(STW)。
- 筛选回收:按垃圾量回收优先级回收区域。
- 优点:
- 更少的内存碎片。
- 可控制停顿时间。
- 适用场景:
- 大内存应用和需要稳定停顿时间的场景。
3.5 ZGC(Z Garbage Collector)
- 特点:
- 以超低延迟为目标,停顿时间通常在 10 毫秒以内。
- 使用染色指针(Colored Pointers)和内存压缩技术。
- 参数:
-XX:+UseZGC
- 优点:
- 适合超大堆(TB 级别)。
- 几乎不会出现长时间的 STW。
- 缺点:
- 暂时不支持所有平台(仅支持 64 位操作系统)。
- 适用场景:
- 延迟敏感的大型应用。
3.6 Shenandoah GC
- 特点:
- 类似于 ZGC,目标是低延迟。
- 并发压缩堆内存,减少停顿时间。
- 参数:
-XX:+UseShenandoahGC
- 优点:
- 停顿时间短,适合低延迟场景。
- 缺点:
- 实现复杂,可能对 CPU 要求较高。
4. 垃圾回收器的选择
垃圾回收器 | 特点 | 适用场景 |
---|---|---|
Serial GC | 单线程,简单高效 | 单线程应用,内存较小的场景 |
Parallel GC | 高吞吐量,多线程并行 | 后台批处理、大型数据计算任务 |
CMS GC | 低延迟,减少停顿 | 响应时间要求高的服务,如 Web 服务 |
G1 GC | 平衡吞吐量与延迟 | 大内存应用,停顿时间敏感的场景 |
ZGC | 超低延迟,支持大堆 | 延迟敏感的超大内存应用(如机器学习、数据分析) |
Shenandoah GC | 低延迟,并发内存压缩 | 高并发、低延迟应用 |
5. 如何监控和优化垃圾回收
5.1 常用监控工具
- JVM 内置工具:
jstat
:监控堆内存、GC 行为。jmap
:生成堆快照。jconsole
和VisualVM
:图形化界面监控。
- 第三方工具:
- Prometheus + Grafana:监控 JVM 指标。
- Java Flight Recorder (JFR):性能分析。
5.2 优化建议
- 合理配置 JVM 参数:
- 堆大小:
-Xms
和-Xmx
。 - 年轻代与老年代比例:
-XX:NewRatio
。 - 垃圾回收器选择:根据场景选择合适的 GC。
- 堆大小:
- 减少对象分配:
- 优化代码逻辑,避免过多短生命周期对象。
- 使用对象池(如线程池、连接池)。
- 监控 GC 行为:
- 定期检查 GC 日志,分析停顿时间和频率。
6. 总结
Java 垃圾回收器是 JVM 内存管理的核心,它通过多种策略和算法自动清理内存中的垃圾对象,提高程序运行效率。选择合适的垃圾回收器需要综合考虑应用场景、延迟要求和吞吐量需求:
- 低延迟场景:选择 CMS、G1、ZGC 或 Shenandoah。
- 高吞吐量场景:选择 Parallel GC。
- **普通场景
**:选择默认的 G1 GC(JDK 9+)。
理解不同垃圾回收器的工作原理和适用场景是优化 Java 应用性能的关键。