java采用可达性分析算法判断对象存活,以gc roots为起点:虚拟机栈中局部变量、方法区静态变量与常量、本地方法栈jni引用及活动线程本身;能通过强引用链到达的对象视为可达并保留,否则标记为不可达并回收。

Java垃圾回收机制不看引用计数,而是靠可达性分析算法来判断一个对象是否还“活着”。核心就一句话:从一组固定起点出发,能“摸得到”的对象就留下,摸不到的才可能被回收。
GC Roots 是哪些对象?
这些是判定的“锚点”,本身不会被回收,包括:
- 虚拟机栈中正在使用的局部变量、方法参数所引用的对象
- 方法区(元空间)里的静态变量引用的对象
- 运行时常量池中引用的对象(比如字符串常量池里的字符串)
- 本地方法栈中 JNI(即 native 方法)持有的引用对象
- 正在执行的 Java 线程本身,以及它的栈帧里涉及的引用
怎么才算“可达”?
从任意一个 GC Root 开始,顺着所有强引用往下找,能走到的对象就是可达的。这个过程会形成一条或多条“引用链”。只要存在至少一条链连到某个对象,它就被认为还存活。
比如:A a = new A(); 中的 a 在栈上,它指向的 A 实例就通过这条链与 GC Root(局部变量)相连 → 可达 → 不回收。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
循环引用为什么不影响判定?
两个对象互相引用(如 A 持有 B,B 持有 A),但外部没有任何 GC Root 能到达它们 —— 那整条环就“悬空”了,无法从根出发访问到。可达性分析只认“有没有路”,不关心路上是不是绕圈。所以这种对象会被准确识别为不可达,最终被回收。
这也是 Java 不用引用计数法的关键原因:它天然解决循环引用导致的内存泄漏问题。
不可达 ≠ 立刻回收
一个对象被判定为不可达后,还要经历两次标记:
- 第一次标记:进入“即将回收”队列,同时检查是否重写了
finalize()(已弃用)或注册了清理逻辑 - 第二次标记:若对象在第一次标记后重新与 GC Root 建立了强引用(极少见),就“逃过一劫”;否则正式列为可回收对象
现代 JVM(如 JDK 8+)基本忽略 finalize(),所以两次标记更多是历史兼容设计,实际回收流程更直接。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










