JVM垃圾回收过程及常用方法
一、垃圾回收(GC)是什么?
垃圾回收是JVM自动管理内存的机制,负责回收不再使用的对象占用的内存空间。程序员无需手动释放内存,避免了内存泄漏和野指针问题。GC通过"可达性分析算法"(从GC Roots对象出发,遍历引用链)判断对象是否存活。
二、解决什么问题
- 内存泄漏预防:自动回收无用对象,避免程序长期运行后内存耗尽。
- 减少手动管理错误:消除
malloc/free
或new/delete
不匹配导致的问题。 - 内存碎片整理:通过压缩(Compacting)减少内存碎片,提高内存利用率。
三、垃圾回收过程(分代收集模型)
JVM堆分为新生代(Young Generation)和老年代(Old Generation):
- 对象分配:
- 新对象存入Eden区。
- Eden满时触发 Minor GC。
- Minor GC过程:
- 存活对象从Eden复制到Survivor区(S0/S1)。
- 对象每熬过一次GC年龄+1,达到阈值(默认15)则晋升老年代。
- 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 : 目标最大停顿时间
六、应用场景
- Web服务:G1/ZGC(低延迟,避免请求卡顿)。
- 大数据处理:Parallel Scavenge(高吞吐量,快速处理数据)。
- 客户端应用:Serial(资源占用少)。
- 云原生环境:ZGC/Shenandoah(容器内存敏感,毫秒级停顿)。
七、重要注意事项
- 避免频繁Full GC:
- 优化对象生命周期(避免小对象直接进入老年代)。
- 增大堆内存或调整
-XX:NewRatio
(新生代/老年代比例)。
- GC日志分析:bash
-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
- 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行为,针对性优化参数。