GC Roots是JVM可达性分析中“一定存活”的引用起点,包括虚拟机栈中局部变量、方法区静态变量与常量、本地方法栈JNI引用等;其根属性源于运行时状态保障,而非对象本身特性。

GC Roots 不是某种特殊对象,而是 JVM 在执行可达性分析时认定“一定存活、不可回收”的一组引用起点。它们构成垃圾回收的锚点,所有能从这些起点出发、沿引用链到达的对象都被视为存活;反之,断开连接的对象才会被标记为待回收垃圾。局部变量、静态变量和常量引用之所以具备“根”属性,关键不在于它们存储了什么值,而在于其生命周期由 JVM 运行时状态严格保障——只要栈帧存在、类未卸载、常量未被清理,它们就天然具备“不可被回收”的权威性。
局部变量为什么是 GC Roots
方法调用时,JVM 在虚拟机栈中创建栈帧,其中局部变量表保存着当前方法内声明的引用变量(如 User user = new User();)。只要该方法尚未返回,栈帧就持续存在,这个局部变量就始终是 GC Root。它不关心变量后续是否被使用,只认栈帧的存续状态。
- 方法执行中:user 是 GC Root,它引用的 User 对象一定存活
- 方法返回后:栈帧弹出,user 引用消失,若无其他引用指向该 User 实例,它立刻变为不可达
- 即使代码写成 user = null;,只要栈帧还在,user 本身仍是 GC Root(只是它引用的值为 null)
静态变量为何具有强根属性
类加载后,其静态字段被存放在方法区(或元空间),随类的整个生命周期存在,直到类被卸载(极少见)。因此,public static User instance = new User(); 中的 instance 本身就是 GC Root,它所引用的对象不会因业务逻辑结束而自动失效。
- 静态变量属于类,不是实例,一个类只有一个副本
- 只要类没被卸载,instance 就永远是 GC Root,哪怕长期不访问
- 这也是静态集合(如 static Map)容易引发内存泄漏的根本原因:它持续持有对象引用,阻止 GC 回收
常量引用如何成为 GC Roots
方法区中的运行时常量池里,编译期确定的字符串字面量(如 final String NAME = "张三";)或基本类型常量,一旦加载进常量池,就被 JVM 视为“永久存活”。它们本身不是对象,但其所引用的字符串实例(如 "张三" 对应的 String 对象)会因该常量引用而成为 GC Root 的间接目标。
- 注意:仅限编译期确定的常量(含 final + 编译期可计算值),运行时 new 出的字符串不算
- 字符串常量池中的对象,只要被常量直接引用,就不会被 GC 清理
- 这种机制支撑了字符串 intern 行为的稳定性,但也可能意外延长对象生命周期










