gc roots 是一组必须活跃的引用而非固定对象,包括虚拟机栈局部变量、方法区静态字段与常量、jni 引用、运行中线程对象等;jvm 通过 oopmap 和安全点机制在 stw 下快速枚举。

Java 垃圾回收的根集合(GC Roots)不是一堆固定对象,而是一组必须活跃的引用,是可达性分析的起点。只要一个对象能通过引用链从这些根引用到达,它就被视为存活;否则,就可能被回收。
GC Roots 包含哪些内容
这些引用来源覆盖 JVM 运行时最核心的活跃区域,主要包括:
虚拟机栈中各栈帧的局部变量和方法参数
每个线程当前执行的方法里,还没出作用域的引用变量(比如Object obj = new Object();中的obj)。方法区中的静态字段(类变量)引用
如public static Map<string object> cache = new HashMap();</string>中cache所持有的引用。方法区中的常量引用
字符串常量池(StringTable)中对字符串实例的引用,例如"hello"在常量池中指向堆中某个 String 对象。本地方法栈中 JNI 引用
Java 调用 C/C++ 代码时,由本地代码主动持有的 Java 对象引用(如通过NewGlobalRef创建的全局引用)。正在运行的 Java 线程对象本身
线程实例、其内部锁对象(如synchronized持有的 Monitor)、阻塞队列中的等待对象等,都可能构成根引用。
注意:GC Roots 是引用,不是对象本身。例如,栈里的变量 a 是根,它指向的那个 Object 实例不是根。
怎么查找 GC Roots
查找不是靠人工遍历,而是由 JVM 在特定时机自动完成,过程依赖两个关键机制:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
OopMap(Ordinary Object Pointer Map)
HotSpot JVM 在编译或解释执行时,在“安全点”位置记录下当前栈帧和寄存器中哪些位置存放着对象引用。GC 触发时,直接读取 OopMap 就能快速定位所有活跃引用,无需逐字节扫描栈内存。安全点(Safepoint)与安全区域(Safe Region)
JVM 不允许在任意指令处暂停线程做 GC,只允许在线程到达安全点后停顿。常见安全点包括:方法调用返回、循环跳转、异常抛出等位置。所有用户线程必须跑到最近的安全点才能被挂起,然后统一枚举根。
实际查找过程是:
- 用户线程暂停(Stop-The-World)
- JVM 从每个线程的栈顶开始,结合 OopMap 解析出所有引用位置
- 扫描方法区的静态字段、常量池、JNI 全局引用表等全局结构
- 合并所有引用,构成本次 GC 的根集合
补充:Young GC 时,老年代中指向年轻代的引用也会被加入 Roots(跨代引用),否则年轻代里被老年代“牵着”的对象会被误判为垃圾。
为什么不能边运行边查根
因为根集合必须在一个一致性快照中确定。如果线程一边执行一边修改引用(比如刚把某个变量设为 null,GC 却没看到),会导致分析结果错误。所以根枚举阶段必须 STW,哪怕 G1 或 ZGC 也逃不开这一环。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










