java中判断对象是否可回收依赖可达性分析算法,gc roots是必须存活的对象起点,包括虚拟机栈局部变量、方法区静态变量与常量、同步块锁定对象、jni引用及活跃线程本身。

Java 中判断一个对象是否该被回收,靠的是可达性分析算法,而这个算法的起点就是 GC Roots。简单说,GC Roots 是一组 JVM 认为“必须存活”的对象,从它们出发,顺着引用链能到达的对象就活着,到不了的就被标记为可回收。
虚拟机栈中的局部变量和参数
这是最常见的一类 GC Root。每个线程执行方法时,会在虚拟机栈中创建栈帧,其中的本地变量表里存着方法内声明的局部变量、形参等引用。只要方法没执行完,这些变量所引用的对象就一定可达。
- 比如
void process() { List<string> list = new ArrayList(); }</string>中的list就是 GC Root - 方法返回后栈帧弹出,这个引用就消失了,对应对象可能变成不可达
方法区里的静态变量和常量
类加载进内存后,它的静态字段(static)和字符串常量池中的字符串字面量,都属于 GC Roots。它们的生命周期通常与类加载器绑定,只要类没卸载,这些引用就一直有效。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
public static final String MSG = "hello";中的字符串常量是 GC Root -
private static Cache cache = new Cache();中的cache也是 GC Root - 注意:普通实例变量不是 GC Root,只有
static修饰的才算
同步块中被锁住的对象
当代码进入 synchronized(obj) 块时,JVM 会确保 obj 在整个同步期间不被回收,否则可能导致锁失效甚至崩溃。所以正在被同步锁持有的对象,也属于 GC Root。
- 哪怕
obj只在同步块内使用,只要还没退出块,它就受保护 - 退出同步块后,这层保护就解除,是否回收取决于其他引用链
本地方法栈中的 JNI 引用
JNI 调用 Native 代码时,Java 对象可能被 C/C++ 代码持有。JVM 会通过全局引用(NewGlobalRef)或局部引用(如函数参数)来维持这些对象的存活状态,防止它们在 Native 层还在使用时被误收。
- 全局引用需手动释放,否则会导致内存泄漏
- 局部引用在 JNI 函数返回后自动失效,但函数执行期间它是有效的 GC Root
活跃线程本身
所有正在运行的 Java 线程(包括主线程、守护线程、用户线程)都是 GC Root。线程对象自身及其内部栈帧里的引用,共同构成可达性分析的起点之一。
- 新创建但还没 start 的线程对象不算活跃,不作为 GC Root
- 已终止的线程对象,如果还有强引用指向它,它本身可能仍可达,但不再贡献新的 GC Root
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










