JVM 垃圾回收机制详解
垃圾回收(GC)是 Java 相比 C/C++ 最大的优势之一。理解 GC 的工作原理,是排查内存问题和性能调优的基础。
分代模型
JVM 堆内存分为年轻代(Young Generation)和老年代(Old Generation)。
mermaid
graph LR
Heap[JVM Heap] --> Young[年轻代]
Heap --> Old[老年代]
Young --> Eden[Eden 区]
Young --> S1[Survivor 0]
Young --> S2[Survivor 1]对象的生命周期
- 新对象分配在 Eden 区
- Eden 满了触发 Minor GC,存活对象复制到 Survivor 0
- 来回交换,年龄达到阈值(默认 15)的对象晋升到老年代
- 老年代满了触发 Major GC / Full GC
为什么用复制算法?年轻代中绝大多数对象「朝生夕死」,存活率极低,复制少量存活对象比标记清除高效得多。
垃圾判定:可达性分析
从 GC Roots 出发,沿引用链遍历,不可达的对象就是垃圾。
GC Roots 包括:虚拟机栈中的局部变量、方法区中的静态变量和常量、本地方法栈中的 JNI 引用、活跃线程。
mermaid
graph TD
Root1[GC Root: 局部变量] --> A[对象 A]
Root2[GC Root: 静态变量] --> B[对象 B]
A --> C[对象 C]
B --> C
D[对象 D] --> E[对象 E]
E --> D上图中 D 和 E 互相引用但没有 GC Root 到达它们,会被回收。
经典垃圾回收器
Serial GC
单线程回收,适合小型应用和客户端场景。-XX:+UseSerialGC
Parallel GC(吞吐量优先)
Java 8 默认。多线程回收,目标是最大化吞吐量。
bash
-XX:+UseParallelGC
-XX:MaxGCPauseMillis=200G1 GC(停顿时间优先)
Java 9+ 默认。把堆划分为多个 Region,每次只回收收益最高的 Region。
bash
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200G1 的回收过程:初始标记(STW)→ 并发标记 → 最终标记(STW)→ 筛选回收(STW)。
G1 的核心优势:可预测的停顿时间。用户指定目标停顿时间,G1 估算能在该时间内回收多少 Region。
ZGC(低延迟)
Java 11 引入,停顿时间 < 1ms(Java 16+),适合超大堆和低延迟场景。
如何选择 GC
| GC | 适用场景 | 停顿时间 |
|---|---|---|
| Serial | 单核、小堆(< 100MB) | 长 |
| Parallel | 批处理、离线计算 | 中 |
| G1 | 通用、中等堆(4-32GB) | 短可预测 |
| ZGC | 大堆、低延迟 | 极短(< 1ms) |
经验法则:堆 < 4GB 用 G1,堆 > 32GB 用 ZGC,只关心吞吐量用 Parallel。
排查内存问题
查看 GC 日志
bash
# Java 9+
java -Xlog:gc*=info:file=gc.log:time,level,tags:filecount=5,filesize=10m -jar app.jar使用 jstat
bash
jstat -gcutil <pid> 1000 10 # 每秒一次,共 10 次使用 jmap
bash
jmap -histo <pid> | head -20 # 堆直方图
jmap -dump:format=b,file=heap.hprof <pid> # 导出堆 dump用 MAT 或 JProfiler 分析 heap.hprof,查找内存泄漏。
常见内存问题
内存泄漏:静态集合持有对象引用不放。
java
// 典型泄漏:静态 Map 只 put 不 remove
public class Cache {
private static final Map<String, Object> CACHE = new HashMap<>();
}调优建议
bash
-Xms4g -Xmx4g # 堆大小固定
-XX:+UseG1GC # 使用 G1
-XX:MaxGCPauseMillis=200 # 目标停顿 200ms
-XX:+HeapDumpOnOutOfMemoryError # OOM 时自动 dump
-XX:HeapDumpPath=/tmp/heap.hprof小结
JVM GC 的核心思路是分代收集:年轻代用复制算法(存活率低),老年代用标记-清除或标记-整理。理解分代模型、可达性分析和常用 GC 日志排查方法,就能解决大部分内存问题。