JVM垃圾回收的可达性判定以GC Roots为起点,通过引用链判断对象是否可达:虚拟机栈、方法区静态属性与常量、本地方法栈JNI引用及同步锁对象(Java 14+弱化)构成GC Roots;强、软、弱、虚四类引用强度递减,影响回收时机;可达性分析需STW并依赖安全点机制,循环引用无外部接入即整体不可达。

引用数据类型在JVM垃圾回收中的可达性判定,核心在于“从GC Roots出发能否访问到该对象”。只要一条引用链能连通,对象就被视为可达(live),不会被回收;反之,若所有引用链都断开,即为不可达(unreachable),进入回收候选队列。
哪些对象算作GC Roots?
GC Roots不是对象本身,而是JVM认定的“绝对不能被回收”的起点。主要包括:
- 虚拟机栈(栈帧中的局部变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象(如字符串常量池里的String实例)
- 本地方法栈中JNI(Native方法)引用的对象
- 正在被同步锁(synchronized)持有的对象(Java 14+ 中已弱化此条)
引用类型强弱影响可达性判定
JVM将引用分为四类,强度逐级减弱,直接影响GC时是否保留对象:
- 强引用(Strong Reference):如 Object obj = new Object()。只要强引用存在,GC永远不会回收该对象
- 软引用(SoftReference):内存不足时才回收,适合做缓存(如图片缓存)。JVM在OOM前会尝试清空软引用指向的对象
- 弱引用(WeakReference):只存在于一次GC周期内。下一次GC开始时,无论内存是否充足,都会被回收(如ThreadLocalMap中的key)
- 虚引用(PhantomReference):无法通过它获取对象实例,唯一作用是接收对象被回收的系统通知(配合ReferenceQueue使用),常用于资源清理钩子
可达性分析不是实时进行的
GC线程需确保分析过程的一致性,因此必须暂停用户线程(Stop-The-World)。JVM通过安全点(Safepoint)机制,在线程执行到特定位置时触发暂停,再统一扫描GC Roots并标记所有可达对象。这意味着:
- 局部变量即使已超出作用域,只要栈帧未出栈,仍可能被GC Roots持有着
- 对象是否“真正无用”,不取决于程序员主观判断,而取决于此时能否从GC Roots追溯到它
- 循环引用在可达性分析中自然失效——只要整个环路没有外部引用接入,整组对象都会被判定为不可达
常见误解与注意点
容易混淆的地方包括:
- “对象被置为null”不等于立刻不可达——局部变量赋值为null只是断开一个引用,还需看是否还有其他路径可到达
- Finalizer机制已被废弃(Java 9起标记为deprecated),finalize()方法不再保证执行,也不应作为资源释放的主要手段
- 现代JVM(如ZGC、Shenandoah)虽支持并发标记,但可达性判定逻辑不变,只是STW时间大幅缩短
- 方法区(元空间)中的类对象也有自己的可达性规则:只有当类加载器不可达,且该类所有实例都不可达时,类信息才可能被卸载

















