JVM的垃圾回收机制
JVM 的垃圾回收机制(Garbage Collection, GC)是自动管理堆内存的进程,通过识别和回收不再使用的对象,释放内存空间,防止内存泄漏。它基于可达性分析判断对象存活,结合分代回收策略(如新生代、老年代),使用多种算法(如标记-清除、复制)优化性能。
1. 垃圾回收机制概述
作用
- 自动回收堆中无引用对象,释放内存。
- 避免手动管理(如 C 的
free()
)。
管理区域
- 堆:GC 主要目标(对象和数组)。
- 方法区:回收废弃常量和无用类(较少)。
核心步骤
- 标记:识别哪些对象是垃圾。
- 回收:清除垃圾,整理内存(可选)。
2. 如何判断对象可回收
(1) 可达性分析
- 原理:
- 从 GC Roots 开始,追踪引用链。
- 未被引用的对象视为垃圾。
- GC Roots:
- 虚拟机栈中的局部变量。
- 方法区中的静态变量、常量。
- 本地方法栈中的 JNI 引用。
- 示例:
Object a = new Object(); // 可达
a = null; // 不可达,下次 GC 回收
(2) 引用类型
- 强引用:
Object o = new Object()
,不回收。 - 软引用:
SoftReference
,内存不足时回收。 - 弱引用:
WeakReference
,下次 GC 回收。 - 虚引用:
PhantomReference
,跟踪回收状态。
(3) Finalize 方法
- 对象不可达时,可执行
finalize()
自救。 - 仅执行一次,若仍不可达则回收。
@Override
protected void finalize() throws Throwable {
System.out.println("Self save");
this.ref = this; // 自救
}
3. 分代回收策略
堆分代
- 新生代(Young Generation):
- Eden:新对象创建。
- Survivor(From、To):存活对象。
- 老年代(Old Generation):
- 长期存活对象。
- 比例:默认新生代:老年代 = 1:2。
分代假设
- 弱分代假设:大部分对象朝生夕死。
- 强分代假设:存活越久越难回收。
GC 类型
- Minor GC:
- 清理新生代,触发频繁,速度快。
- Major GC / Full GC:
- 清理整个堆,耗时长,含老年代。
4. 垃圾回收算法
(1) 标记-清除(Mark-Sweep)
- 过程:
- 标记可达对象,清除未标记对象。
- 优点:简单。
- 缺点:内存碎片。
(2) 复制(Copying)
- 过程:
- 将存活对象复制到另一区域,清空原区域。
- 优点:无碎片,适合新生代。
- 缺点:内存利用率低(一半空闲)。
(3) 标记-整理(Mark-Compact)
- 过程:
- 标记后,将存活对象移到一端,清除剩余。
- 优点:无碎片,适合老年代。
- 缺点:整理耗时。
(4) 分代收集
- 新生代:复制算法(Eden -> Survivor)。
- 老年代:标记-清除或标记-整理。
5. 垃圾回收器
常见回收器(HotSpot JVM)
- Serial:单线程,适合小应用。
- Parallel:多线程并行,吞吐量高。
- CMS(Concurrent Mark Sweep):
- 并发标记-清除,低停顿。
- 缺点:碎片多。
- G1(Garbage First):
- 分区管理,预测停顿时间。
- 适合大堆,低延迟。
- ZGC / Shenandoah(JDK 11+):
- 超低停顿(<10ms),适合超大堆。
执行过程(G1 示例)
- 初始标记(STW):标记 GC Roots。
- 并发标记:追踪引用。
- 最终标记(STW):修正标记。
- 筛选回收:清理垃圾区域。
6. 触发条件
- Minor GC:Eden 满。
- Full GC:
- 老年代满。
- 元空间不足(
-XX:MaxMetaspaceSize
)。 System.gc()
(建议性)。
延伸与面试角度
- STW(Stop The World):
- GC 时暂停应用线程。
- CMS、G1 减少 STW。
- 调优参数:
-Xms
、-Xmx
:堆大小。-XX:+UseG1GC
:指定 G1。-XX:MaxGCPauseMillis
:目标停顿。- 内存泄漏:
- 对象长期可达(如静态集合)。
- 面试点:
- 问“算法”时,提标记-清除 vs 复制。
- 问“回收器”时,提 G1 和 CMS。
示例
public class GCTest {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
while (true) {
list.add(new Object()); // 触发 GC
}
}
}
总结
JVM 垃圾回收通过可达性分析标记垃圾,分代策略(新生代复制,老年代标记-整理)回收内存,使用回收器(如 G1)优化性能。面试时,可画堆分代图或提调优参数,展示理解深度。