Skip to content

JVM垃圾回收过程及常用方法

一、垃圾回收(GC)是什么?

垃圾回收是JVM自动管理内存的机制,负责回收不再使用的对象占用的内存空间。程序员无需手动释放内存,避免了内存泄漏和野指针问题。GC通过"可达性分析算法"(从GC Roots对象出发,遍历引用链)判断对象是否存活。


二、解决什么问题

  1. 内存泄漏预防:自动回收无用对象,避免程序长期运行后内存耗尽。
  2. 减少手动管理错误:消除malloc/freenew/delete不匹配导致的问题。
  3. 内存碎片整理:通过压缩(Compacting)减少内存碎片,提高内存利用率。

三、垃圾回收过程(分代收集模型)

JVM堆分为新生代(Young Generation)和老年代(Old Generation):

  1. 对象分配
    • 新对象存入Eden区
    • Eden满时触发 Minor GC
  2. Minor GC过程
    • 存活对象从Eden复制到Survivor区(S0/S1)。
    • 对象每熬过一次GC年龄+1,达到阈值(默认15)则晋升老年代。
  3. Full GC过程
    • 老年代空间不足时触发,回收整个堆(包括新生代、老年代、方法区)。
    • 通常伴随"Stop-The-World"(STW),暂停所有应用线程。

四、常用垃圾收集器(JDK8+重点)

JDK8默认:Parallel Scavenge(新生代) + Parallel Old(老年代)

收集器适用区域特点JDK支持
Serial新生代单线程,简单高效(适合客户端应用)所有版本
Parallel Scavenge新生代多线程,吞吐量优先(JDK8默认)JDK1.7+
CMS老年代并发标记清除,低停顿(但内存碎片多)JDK9前
G1全堆分区收集,可预测停顿(JDK9+默认)JDK7u4+
ZGC全堆并发标记整理,停顿<10ms(TB级堆)JDK11+
Shenandoah全堆低延迟(与ZGC竞争),无分代JDK12+

五、核心参数与调优示例

java
// 启动参数示例:使用G1收集器,最大堆4GB,目标停顿200ms
java -XX:+UseG1GC -Xmx4g -XX:MaxGCPauseMillis=200 MyApp

// 常用参数:
// -XX:+UseSerialGC        : 使用Serial收集器
// -XX:+UseParallelGC      : 使用Parallel Scavenge
// -XX:+UseConcMarkSweepGC : 使用CMS
// -XX:+UseZGC             : 使用ZGC(JDK11+)
// -XX:MaxGCPauseMillis=n  : 目标最大停顿时间

六、应用场景

  1. Web服务:G1/ZGC(低延迟,避免请求卡顿)。
  2. 大数据处理:Parallel Scavenge(高吞吐量,快速处理数据)。
  3. 客户端应用:Serial(资源占用少)。
  4. 云原生环境:ZGC/Shenandoah(容器内存敏感,毫秒级停顿)。

七、重要注意事项

  1. 避免频繁Full GC
    • 优化对象生命周期(避免小对象直接进入老年代)。
    • 增大堆内存或调整-XX:NewRatio(新生代/老年代比例)。
  2. GC日志分析
    bash
    -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
  3. ZGC/Shenandoah限制
    • 需Linux/x64环境(Windows/macOS支持较晚)。
    • JDK11+推荐生产环境使用。

八、总结

维度要点
核心思想自动内存管理,基于分代假设(新对象易消亡,老对象难回收)。
关键算法标记-清除(CMS)、标记-复制(Minor GC)、标记-整理(Serial Old, ZGC)。
演进趋势从吞吐量优先(Parallel)到低延迟优先(G1/ZGC/Shenandoah)。
调优核心减少STW时间,平衡吞吐量(Throughput)与延迟(Latency)。

💡 建议:

  • JDK8用户:优先使用G1(-XX:+UseG1GC)。
  • JDK11+用户:直接迁移到ZGC,尤其大内存场景。
    通过工具(VisualVM, GCViewer)监控GC行为,针对性优化参数。