JVM 垃圾回收机制
如何判断对象是否存活?
1. 引用计数法
每个对象有一个引用计数器,被引用时 +1,引用失效时 -1,计数为 0 则可回收。
缺点:无法解决循环引用问题。
java
// 循环引用示例
Object a = new Object();
Object b = new Object();
a.ref = b; // a 引用 b
b.ref = a; // b 引用 a
a = null;
b = null;
// 此时 a、b 对象互相引用,计数都不为 0,但实际上已不可达2. 可达性分析(JVM 使用)
从 GC Roots 出发,沿引用链遍历,不可达的对象即为垃圾。
GC Roots 包括:
├── 虚拟机栈中引用的对象
├── 方法区中类静态属性引用的对象
├── 方法区中常量引用的对象
├── 本地方法栈中 JNI 引用的对象
└── 被同步锁(synchronized)持有的对象垃圾回收算法
1. 标记-清除(Mark-Sweep)
标记阶段: [■][□][■][□][■][□][■]
清除阶段: [■][ ][■][ ][■][ ][■]缺点:产生内存碎片
2. 标记-复制(Copying)
将内存分为两块,每次只使用一块,GC 时将存活对象复制到另一块。
Eden + S0 S1
[■][□][■][□][ ][ ][ ] → [■][■][ ][ ][ ][ ][ ]优点:无碎片,适合年轻代(存活对象少)
3. 标记-整理(Mark-Compact)
标记后,将存活对象向一端移动,然后清理边界外的内存。
标记: [■][□][■][□][■][□][■]
整理: [■][■][■][■][ ][ ][ ]优点:无碎片,适合老年代(存活对象多)
分代收集策略
| 区域 | 特点 | 使用算法 |
|---|---|---|
| 年轻代 | 对象存活率低 | 标记-复制 |
| 老年代 | 对象存活率高 | 标记-清除 / 标记-整理 |
垃圾收集器
年轻代收集器
Serial
单线程收集器,GC 时会 Stop-The-World。
bash
-XX:+UseSerialGCParNew
Serial 的多线程版本,常与 CMS 配合使用。
bash
-XX:+UseParNewGCParallel Scavenge
注重吞吐量,适合后台计算型任务。
bash
-XX:+UseParallelGC
-XX:MaxGCPauseMillis=100 # 最大 GC 停顿时间
-XX:GCTimeRatio=99 # 吞吐量目标老年代收集器
Serial Old
Serial 的老年代版本,单线程,标记-整理算法。
Parallel Old
Parallel Scavenge 的老年代版本,多线程,标记-整理算法。
CMS(Concurrent Mark Sweep)
以最短停顿时间为目标,采用标记-清除算法。
初始标记 (STW) → 并发标记 → 重新标记 (STW) → 并发清除bash
-XX:+UseConcMarkSweepGC缺点:
- 产生内存碎片
- 占用 CPU 资源
- 无法处理浮动垃圾
G1 收集器(JDK 9 默认)
将堆划分为多个 Region,可预测停顿时间。
┌────┬────┬────┬────┬────┬────┐
│ E │ S │ O │ O │ E │ H │
├────┼────┼────┼────┼────┼────┤
│ O │ E │ S │ O │ O │ E │
└────┴────┴────┴────┴────┴────┘
E: Eden S: Survivor O: Old H: Humongousbash
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 期望最大停顿时间
-XX:G1HeapRegionSize=4m # Region 大小ZGC(JDK 11+)
低延迟收集器,停顿时间 < 10ms,支持 TB 级堆内存。
bash
-XX:+UseZGC收集器对比
| 收集器 | 算法 | 线程 | 适用场景 |
|---|---|---|---|
| Serial | 复制/整理 | 单线程 | 客户端模式 |
| ParNew | 复制 | 多线程 | 配合 CMS |
| Parallel | 复制/整理 | 多线程 | 高吞吐量 |
| CMS | 标记-清除 | 并发 | 低延迟 |
| G1 | 标记-整理 | 并发 | 大内存低延迟 |
| ZGC | 标记-整理 | 并发 | 超大内存超低延迟 |
GC 日志分析
bash
# 开启 GC 日志
-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10M[0.015s][info][gc] Using G1
[1.234s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause)
25M->5M(256M) 12.345ms关键指标:
- GC 频率
- 停顿时间
- 堆内存变化
