常见垃圾回收算法、垃圾回收器及 JVM 调优
一、常见垃圾回收算法
1. 标记-清除算法(Mark-Sweep)
- 原理:
- 标记阶段:从 GC Roots 出发,标记所有可达对象。
- 清除阶段:回收未被标记的对象(即不可达对象)。
- 特点:
- 优点:简单直接,不需要移动对象。
- 缺点:
- 产生大量内存碎片(影响大对象分配)。
- 标记和清除过程停顿时间长(STW,Stop-The-World)。
- 适用场景:早期 JVM 或小型应用。
2. 复制算法(Copying)
- 原理:
- 将内存分为两块(Eden 和 Survivor),每次只使用一块。
- 存活对象复制到另一块内存,清空原内存。
- 特点:
- 优点:
- 无内存碎片(对象连续存放)。
- 分配内存只需移动指针(效率高)。
- 缺点:
- 内存利用率低(仅使用一半内存)。
- 复制过程需要 STW。
- 优点:
- 适用场景:新生代(Young Generation),对象存活率低。
3. 标记-整理算法(Mark-Compact)
- 原理:
- 标记阶段:标记所有可达对象。
- 整理阶段:将存活对象向内存一端移动,清理边界外空间。
- 特点:
- 优点:
- 无内存碎片(对象连续存放)。
- 适合老年代(对象存活率高)。
- 缺点:
- 整理过程需要 STW,停顿时间较长。
- 优点:
- 适用场景:老年代(Old Generation)。
4. 分代收集算法(Generational Collection)
- 原理:
- 将堆内存分为新生代(Young Gen)、老年代(Old Gen)和元空间(Metaspace)。
- 不同区域采用不同回收算法:
- 新生代:复制算法(对象存活率低)。
- 老年代:标记-清除或标记-整理(对象存活率高)。
- 特点:
- 优点:结合不同算法优势,提高效率。
- 缺点:实现复杂。
- 适用场景:现代 JVM 的主流方案(如 HotSpot)。
二、常见垃圾回收器
1. Serial GC(串行垃圾回收器)
- 特点:
- 单线程执行 GC,STW 时间长。
- 适用于客户端应用或小型 JVM。
- 适用场景:单核 CPU 或小内存应用(如嵌入式系统)。
2. Parallel GC(并行垃圾回收器)
- 特点:
- 多线程执行 GC,提高吞吐量(适合 CPU 密集型应用)。
- 仍使用 STW,但停顿时间比 Serial GC 短。
- 适用场景:多核 CPU 的批处理任务(如大数据计算)。
3. CMS(Concurrent Mark-Sweep)
- 特点:
- 并发标记和清除:大部分阶段与用户线程并发执行,减少 STW 时间。
- 缺点:
- 会产生内存碎片。
- 可能出现“Concurrent Mode Failure”(并发失败时退化为 Serial Old)。
- 适用场景:低延迟应用(如 Web 服务)。
- 注意:JDK 9 后被废弃,推荐 G1。
4. G1(Garbage-First)
- 特点:
- 分代 + 区域化:将堆划分为多个 Region,灵活调整新生代和老年代大小。
- 并发 + 并行:部分阶段并发执行,减少 STW 时间。
- 可预测停顿:通过目标停顿时间(Pause Time Goal)控制 GC 行为。
- 适用场景:大内存、低延迟应用(如微服务、大数据)。
- JDK 默认:JDK 9+ 默认使用 G1。
5. ZGC(Z Garbage Collector)
- 特点:
- 超低延迟:STW 时间通常 <10ms(适合金融、实时系统)。
- 可扩展性:支持 TB 级堆内存。
- 并发标记和整理:几乎全程并发执行。
- 适用场景:超低延迟应用(如交易系统、实时计算)。
- JDK 支持:JDK 11+ 实验性支持,JDK 15+ 正式 GA。
6. Shenandoah GC
- 特点:
- 低延迟:STW 时间与堆大小无关(类似 ZGC)。
- 并发压缩:减少内存碎片。
- 适用场景:低延迟、大内存应用(如云原生服务)。
- JDK 支持:JDK 12+ 实验性支持,JDK 17+ 正式 GA。
三、JVM 调优关键参数
1. 堆内存设置
-Xms<初始堆大小> # 初始堆大小(如 -Xms2g)
-Xmx<最大堆大小> # 最大堆大小(如 -Xmx4g)
-Xmn<新生代大小> # 新生代大小(如 -Xmn1g)
- 建议:
-Xms
和-Xmx
设置为相同值,避免动态调整开销。- 新生代占比通常为堆的 1/3~1/2(如
-Xmn1g
对应-Xmx3g
)。
2. GC 选择
-XX:+UseSerialGC # 使用 Serial GC
-XX:+UseParallelGC # 使用 Parallel GC
-XX:+UseConcMarkSweepGC # 使用 CMS(JDK 9+ 已废弃)
-XX:+UseG1GC # 使用 G1(JDK 9+ 默认)
-XX:+UseZGC # 使用 ZGC(JDK 11+)
-XX:+UseShenandoahGC # 使用 Shenandoah GC(JDK 12+)
3. G1 特定参数
-XX:MaxGCPauseMillis=<毫秒> # 目标最大停顿时间(默认 200ms)
-XX:InitiatingHeapOccupancyPercent=<百分比> # 触发并发 GC 的堆占用率(默认 45%)
4. 元空间(Metaspace)设置
-XX:MetaspaceSize=<大小> # 初始元空间大小(如 -XX:MetaspaceSize=256m)
-XX:MaxMetaspaceSize=<大小> # 最大元空间大小(如 -XX:MaxMetaspaceSize=512m)
5. 监控与诊断
-XX:+PrintGCDetails # 打印 GC 详细日志
-XX:+PrintGCDateStamps # 打印 GC 时间戳
-Xloggc:<文件路径> # 将 GC 日志输出到文件
-XX:+HeapDumpOnOutOfMemoryError # OOM 时生成堆转储文件
-XX:HeapDumpPath=<路径> # 堆转储文件路径
四、JVM 调优策略
1. 新生代调优
- 对象存活率低:增大新生代(减少 Minor GC 频率)。
- 对象存活率高:减小新生代(避免频繁 Full GC)。
2. 老年代调优
- 老年代空间不足:
- 增大堆大小(
-Xmx
)。 - 调整
IHOP
(-XX:InitiatingHeapOccupancyPercent
)提前触发并发 GC。
- 增大堆大小(
- 频繁 Full GC:
- 检查是否有内存泄漏(使用 MAT 或 VisualVM 分析堆转储)。
- 优化代码减少大对象分配。
3. 低延迟场景
- 使用 G1/ZGC/Shenandoah 替代 CMS/Parallel GC。
- 设置较小的
-XX:MaxGCPauseMillis
(如 100ms)。
4. 高吞吐场景
- 使用 Parallel GC 或 G1(平衡吞吐与延迟)。
- 增大堆大小以减少 GC 频率。
5. 监控与分析
- 使用工具:
- JVisualVM / JConsole(实时监控)。
- MAT(Eclipse Memory Analyzer,分析堆转储)。
- GC 日志分析工具(如 GCViewer、GCEasy)。
五、总结
类别 | 关键点 |
---|---|
垃圾回收算法 | 标记-清除、复制、标记-整理、分代收集(现代 JVM 主流)。 |
垃圾回收器 | Serial(单线程)、Parallel(多线程)、CMS(已废弃)、G1(低延迟)、ZGC/Shenandoah(超低延迟)。 |
JVM 调优 | 堆大小设置、GC 选择、元空间调整、监控工具(GC 日志、MAT)。 |
调优策略 | 新生代/老年代优化、低延迟 vs 高吞吐、内存泄漏排查。 |
适用场景建议:
- 客户端应用:Serial GC 或 Parallel GC。
- Web 服务:G1(默认)或 CMS(旧版 JDK)。
- 金融/实时系统:ZGC 或 Shenandoah。
- 大数据计算:Parallel GC(高吞吐)。
demo配置命令:
java -Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar your_app.jar