1283 字
6 分钟
JVM 垃圾回收如何判断对象可以被回收:引用计数与可达性分析

面试题:JVM 如何判断一个对象可以被回收?

JVM 主要通过**可达性分析(Reachability Analysis)**判断对象是否存活。

需要了解两种方法:

  1. 引用计数法
  2. 可达性分析(Java 主流 JVM 使用的核心方法)

引用计数法#

基本原理#

为每个对象维护一个引用计数器:

  • 当对象被引用时,引用计数增加。
  • 当引用失效时,引用计数减少。
  • 当引用计数为 0 时,对象可以被认为是垃圾。

示例:

Object a = new Object();
a = null;

第一行创建对象,变量 a 指向该对象。

第二行将 a 设为 null,如果没有其他引用指向该对象,它就可能成为垃圾。

缺点:无法单独解决循环引用#

class Node {
Node next;
}
Node a = new Node();
Node b = new Node();
a.next = b;
b.next = a;
a = null;
b = null;

此时:

  • 对象 A 引用对象 B。
  • 对象 B 引用对象 A。
  • 外部变量 a、b 已经不再引用这两个对象。
  • 两个对象之间仍然存在相互引用。

引用计数法可能认为它们仍然存活,因为引用计数没有归零。

结论:引用计数法无法单独解决循环引用问题,不是 Java 主流 JVM 判断对象存活的主要方法。

可达性分析(重点)#

基本原理#

可达性分析从一组称为 GC Roots 的对象出发,沿着引用关系进行遍历。

判断规则:

  • 能够从 GC Roots 到达的对象:暂时认为存活。
  • 无法从任何 GC Roots 到达的对象:被判定为不可达,成为垃圾回收的候选对象。

注意:不可达不代表对象一定会立即被回收。

示例#

Object a = new Object();
Object b = a;
a = null;

虽然 a 已经变成 null,但 b 仍然引用着原来的对象。

如果 b 仍然是 GC Roots 可达的局部变量引用,那么原对象仍然可达,不能仅仅因为 a = null 就认定它是垃圾。

判断对象能否被回收,关键是是否还存在从 GC Roots 到达它的引用路径,而不是某个变量是否为 null。

引用关系示意#

GC Roots
|
v
对象 A
|
v
对象 B
对象 C(没有从 GC Roots 出发的引用路径)
  • 对象 A 可达,因此存活。
  • 对象 B 虽然没有被局部变量直接引用,但可以通过对象 A 到达,因此也存活。
  • 对象 C 不可达,因此可能被回收。

常见的 GC Roots#

面试中需要掌握以下几类:

  1. Java 虚拟机栈中的引用:例如当前方法中的局部变量引用。
  2. 静态字段引用的对象:例如类的静态变量持有的对象。
  3. JNI 引用:Java 调用本地代码时,本地代码持有的相关引用。
  4. JVM 内部引用:例如某些运行时数据结构持有的对象。

注意:静态变量引用的对象并非永远不能回收。如果静态字段被清空,且对象没有其他可达路径,它仍可能成为垃圾。

面试回答模板#

问:JVM 如何判断一个对象可以被回收?

答:

JVM 主要通过可达性分析判断对象是否存活。它从 GC Roots 出发,沿着对象引用关系进行遍历。如果一个对象无法从任何 GC Roots 到达,就会被判定为不可达对象,成为垃圾回收的候选对象。

常见的 GC Roots 包括虚拟机栈中的引用、静态字段引用、JNI 引用以及 JVM 内部引用。

另外,引用计数法通过统计对象的引用数量判断对象是否存活,但无法单独解决循环引用问题,因此不是 Java 主流 JVM 判断对象存活的主要方法。

需要记住的重点#

  • JVM 判断对象是否存活的核心方法:可达性分析。
  • 可达性分析的起点:GC Roots。
  • 能从 GC Roots 到达的对象:暂时认为存活。
  • 无法从 GC Roots 到达的对象:不可达,成为垃圾回收的候选对象。
  • 引用计数法的主要缺点:无法单独解决循环引用问题。
  • 对象不可达不代表一定立即回收。

自测题#

题目 1#

Object a = new Object();
Object b = a;
a = null;

假设 b 仍然是 GC Roots 可达的局部变量引用,原对象能否被回收?

答案:不能被当作垃圾回收,因为 b 仍然引用着原对象。

题目 2#

两个对象互相引用,但没有任何 GC Roots 能够到达它们,这两个对象能否被回收?

答案:可以成为垃圾回收的候选对象。可达性分析能够识别这种循环引用导致的不可达对象。

题目 3#

对象不可达后,JVM 是否一定立即回收它?

答案:不一定。不可达意味着它成为垃圾回收的候选对象,实际回收时间由 JVM 的垃圾回收机制决定。

JVM 垃圾回收如何判断对象可以被回收:引用计数与可达性分析
https://blog.xqcherry.top/posts/interview/jvm/gc-reachability-analysis/
作者
xqcherry
发布于
2026-10-09
许可协议
CC BY-NC-SA 4.0