可达性分析算法以gc roots为起点沿强引用链标记存活对象,未被任何链触达的对象即为垃圾;gc roots包括虚拟机栈局部变量、方法区静态变量与常量、jni引用、被锁对象及运行中线程。

可达性分析算法不统计引用次数,而是从一组确定的“起点”出发,顺着强引用往下找,能摸到的对象就留下,摸不到的就标记为垃圾。关键不在对象有没有被引用,而在它能不能从 GC Roots 出发、连成一条不断开的路径。
GC Roots 是哪些对象
这些是 JVM 明确保证“此刻一定活跃”的引用源头,本身不会被回收:
- 虚拟机栈中正在执行的方法里的局部变量(比如 String s = new String("a") 中的 s)
- 方法区(元空间)中类的静态变量(如 public static List
cache ) - 方法区常量池中的常量引用(如 public static final String MSG = "ok")
- 本地方法栈中 JNI 调用所持有的 Java 对象
- 被 synchronized 锁住的对象(HotSpot 实现中会纳入)
- 正在运行的 Java 线程本身(包括它的栈帧和内部引用)
怎么顺着引用链“摸”出存活对象
JVM 以所有 GC Roots 为起点,并发或串行地遍历引用图:
- 采用深度优先或广度优先方式,沿着 obj.field、array[i]、map.get(key) 这类强引用向下走
- 只要某条路径能抵达一个对象,它就被打上“存活”标记——哪怕只有一条链连上就行
- 循环引用不影响结果:A 引用 B、B 引用 A,但两者都没连向任何 GC Root → 整个环不可达 → 全部被标记为可回收
- 软引用、弱引用、虚引用不构成有效路径,不会让对象“活下来”
不可达对象不是立刻消失
被判定为不可达后,对象进入待回收状态,但不等于马上释放内存:
- 现代 JVM(JDK 8+)基本跳过 finalize(),不再提供“自救”机会
- 部分回收器(如 G1、ZGC)会用三色标记法分阶段处理:白色(未访问)、灰色(已标记但子引用未扫)、黑色(完全扫描确认存活)
- 真正回收发生在后续阶段(如清除、整理、复制),与可达性分析本身是分离的
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











