Java采用可达性分析算法判定对象存活:从GC Roots出发搜索引用链,不可达对象需经两次标记才被回收,循环引用因无GC Root路径而被准确识别为垃圾。

Java 垃圾回收器不靠“对象是否被显式删除”来判断,而是通过对象是否还被程序逻辑所触及来决定——核心依据是可达性分析算法,这是 JVM 实际采用的唯一标准。
可达性分析:从 GC Roots 出发找活对象
JVM 会从一组被称为 GC Roots 的特殊对象出发,沿着所有引用链向下搜索。能被这条链“触达”的对象,就认为还在使用中;一旦某个对象从任何 GC Root 都无法到达,它就被标记为“不可达”,进入待回收队列。
常见的 GC Roots 包括:
- 虚拟机栈(栈帧中的局部变量表)里引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象(比如字符串常量池里的字符串)
- 本地方法栈中 JNI(即 Native 方法)引用的对象
- 正在被同步锁持有的对象(如 synchronized 锁住的对象)
不是“一判即收”,要经历两次标记
被判定为不可达,不等于立刻销毁。JVM 会给这类对象一次“自救”机会:
立即学习“Java免费学习笔记(深入)”;
- 第一次标记:发现不可达,进入 F-Queue 队列
- 如果对象重写了
finalize()方法且尚未执行过,会被放入一个低优先级的 Finalizer 线程去执行(注意:finalize已被弃用,不推荐使用) - 第二次标记:若对象在
finalize中重新与 GC Roots 建立了有效引用(比如把自己赋给某个静态变量),就会被移出回收名单;否则,正式宣告死亡
引用计数法为什么不用?
虽然原理简单(每多一个引用+1,少一个-1,归零即回收),但它解决不了循环引用问题:
- 比如 A 对象持有 B,B 又持有 A,两者引用计数都不为 0
- 但外部已没有任何变量指向它们,实际已无法访问
- JVM 明确不采用此法,避免内存泄漏风险
赋 null 或离开作用域 ≠ 立刻回收
把引用设为 null 或方法执行结束,只是让对象失去可达路径,属于触发可达性分析的前提条件。真正回收时机由 GC 策略(如 G1、ZGC)、堆内存压力、JVM 参数等共同决定,不会立即发生,也不可控。


















