Java垃圾回收中对象存活分析依赖可达性分析,根集(GC Roots)枚举是第一步,包括静态变量、常量池、虚拟机栈局部变量、JNI引用及被synchronized锁住的对象;OopMap提升枚举效率,安全点确保一致性,安全区域覆盖阻塞线程,共同实现毫秒级Stop-the-World。

Java垃圾回收中对象存活分析依赖“可达性分析”,而根集(GC Roots)枚举是该过程的第一步,也是关键前提。它不靠逐个扫描全局变量或栈帧内容,而是借助元数据结构和运行时约定,在可控开销下快速、准确地定位所有活跃引用起点。
哪些对象能成为GC Roots
GC Roots不是任意对象,而是JVM明确保证“当前绝对不能被回收”的一组引用。主要包括:
- 静态变量引用的对象:类加载后存于方法区的static字段所指向的实例;
- 常量池中的引用:如字符串常量池里驻留的String对象;
- 虚拟机栈中局部变量表里的引用:每个线程栈帧的本地变量槽中正在使用的对象引用;
- 本地方法栈中JNI引用的对象:Java调用C/C++代码时传递并持有的Java对象;
- 被synchronized锁住的对象:作为锁监视器的对象在同步块执行期间必须存活。
OopMap让根枚举变高效
若每次GC都从头遍历整个栈和方法区找引用,耗时不可接受。HotSpot通过OopMap解决这个问题——它是一组编译期生成、运行时维护的映射表,记录了:
- 某类实例中,哪个内存偏移位置存放的是对象引用;
- 某个安全点处,栈上哪些寄存器或栈槽存储着有效引用。
这样,GC只需读取当前线程在安全点处对应的OopMap,就能直接知道哪些位置是GC Roots,无需解析字节码或猜测数据类型。
立即学习“Java免费学习笔记(深入)”;
安全点确保枚举一致性
根枚举必须在对象引用关系“静止”的快照中进行,否则一边扫描一边修改引用链会导致漏判或误判。因此JVM要求线程必须到达安全点才能暂停:
- 安全点通常设在方法调用返回前、循环跳转后、异常抛出位置等指令边界;
- 线程采用主动轮询方式:GC发起时设置中断标志,线程执行到安全点就检查该标志并挂起;
- 避免因线程长时间执行某条指令(如空循环)而无法响应GC请求。
安全区域覆盖休眠与阻塞线程
安全点机制对运行中的线程有效,但对sleep、wait、blocked状态的线程无效——它们无法主动轮询中断标志。为此引入安全区域:
- 线程进入sleep或wait前,先声明自己进入安全区域;
- GC可忽略这些线程,继续执行根枚举;
- 线程唤醒准备继续执行时,会检查GC是否已完成;未完成则等待,完成后才恢复运行。
整个过程围绕“准确性”与“低延迟”平衡展开:停顿用户线程不可避免,但通过OopMap压缩搜索范围、用安全点控制停顿时机、以安全区域兜底特殊状态,使Stop-the-World时间控制在毫秒级。


















