1. 概述
本文将快速介绍不同 JVM 垃圾收集(GC) 实现的基础知识,并演示如何在应用程序中启用特定类型的垃圾收集器。
2. 垃圾收集简介
从名称看,垃圾收集似乎只是查找并删除内存中的垃圾。但实际上,垃圾收集器会追踪 JVM 堆空间中的每个对象,并清除不再使用的对象。
GC 工作流程主要分为两个简单步骤,称为标记和清除:
- 标记阶段:垃圾收集器识别哪些内存正在使用,哪些未被使用
- 清除阶段:移除标记阶段识别出的无用对象
✅ 优势:
❌ 劣势:
- JVM 需追踪对象引用的创建/删除,会消耗额外 CPU 资源,可能影响大内存请求的性能
- 程序员无法控制释放无用对象的 CPU 时间调度
- 某些 GC 实现可能导致应用不可预测地暂停
- 自动化内存管理效率不如合理的手动内存分配/释放
3. GC 实现类型
JVM 提供四种 GC 实现:
- Serial 垃圾收集器
- Parallel 垃圾收集器
- G1 垃圾收集器
- Z 垃圾收集器
3.1. Serial 垃圾收集器
这是最简单的 GC 实现,采用单线程工作。运行时会冻结所有应用线程,因此不适合多线程应用(如服务器环境)。
Twitter 工程师在 QCon 2012 的演讲中深入分析了 Serial GC 性能,值得参考。
Serial GC 适用于对暂停时间无要求且运行在客户端模式的应用。启用方式:
java -XX:+UseSerialGC -jar Application.java
3.2. Parallel 垃圾收集器
从 Java 5 到 Java 8 的默认 GC,又称吞吐量收集器。与 Serial GC 不同,它使用多线程管理堆空间,但执行 GC 时仍会冻结应用线程。
使用此 GC 可指定:
- 最大 GC 线程数(
-XX:ParallelGCThreads=<N>
) - 最大暂停时间目标(
-XX:MaxGCPauseMillis=<N>
) - 最大吞吐量目标(
-XX:GCTimeRatio=<N>
) - 最大堆内存(
-Xmx<N>
)
启用方式:
java -XX:+UseParallelGC -jar Application.java
3.3. G1 垃圾收集器
G1(Garbage First) 专为多处理器大内存环境设计,自 JDK 7 Update 4 引入。
核心特性:
- 将堆划分为等大小的区域
- 通过并发全局标记阶段(标记阶段)确定对象存活状态
- 优先回收空白区域(清除阶段),因此得名 "Garbage-First"
启用方式:
java -XX:+UseG1GC -jar Application.java
3.4. Java 8 新特性
Java 8u20 引入 字符串去重 功能(-XX:+UseStringDeduplication
),通过将重复字符串值合并到全局 char[]
数组优化堆内存使用。
3.5. Z 垃圾收集器
ZGC(Z Garbage Collector) 是可伸缩的低延迟收集器:
- Java 11 在 Linux 上作为实验性功能引入
- JDK 14 支持 Windows 和 macOS
- Java 15 起转为生产就绪
核心优势:
- 所有昂贵操作并发执行,暂停时间不超过 10ms
- 使用带色指针的加载屏障实现并发操作
- 支持堆内存范围从 8MB 到 16TB
- 暂停时间不随堆大小、存活对象或根集大小增加
⚠️ 注意:
- 与 G1 类似分区堆,但区域大小可变
- 非默认 GC
启用方式:
# JDK 15 之前(需开启实验模式)
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC Application.java
# JDK 15 及之后
java -XX:+UseZGC Application.java
4. 总结
本文分析了主流 JVM 垃圾收集器的实现原理及适用场景。更详细的调优文档可参考 Oracle 官方指南。