可达性分析法(根搜索算法)完整详解

一、定义

可达性分析(Reachability Analysis)Java 虚拟机判断堆中对象是否存活的核心算法 ,用来区分存活对象与垃圾对象,为 GC 回收做标记。 核心思路: 以一组特殊起点 GC Roots(根对象) 为源头,顺着引用链向下遍历所有被引用的对象;

  • 能通过引用链连接到 GC Roots → 可达,存活,不能回收
  • 没有任何引用链连通 GC Roots → 不可达,判定为垃圾,可回收

二、为什么不用「引用计数法」?

早期语言用引用计数(对象被引用 + 1,引用失效 - 1,计数 0 则回收),但有致命缺陷:无法解决循环引用。 示例循环引用:

java

运行

复制代码
Object a = new Object();
Object b = new Object();
a = b;
b = a;
a = null;
b = null;
  • 引用计数法:a、b 互相引用,计数永远不为 0,内存泄漏;
  • 可达性分析法:a、b 和 GC Roots 无通路,判定为垃圾正常回收。

三、GC Roots 有哪些(面试必背 6 大类)

GC Roots 是程序运行时一定存活的对象,作为遍历起点:

  1. 虚拟机栈(栈帧本地变量表)引用的对象 方法局部变量、方法参数;方法执行时栈帧存在,对象存活;方法执行完毕栈帧弹出,引用链断开。

    java

    运行

    复制代码
    public void test(){
        User u = new User(); // u是栈局部变量,User对象是GC Roots可达
    }
  2. 方法区中静态变量引用的对象 static修饰的类成员,只要类未卸载,对象一直可达。

    java

    运行

    复制代码
    class Demo{
        static User user = new User(); // 静态引用,GC Root
    }
  3. 方法区常量池引用的对象 字符串常量池、运行时常量池中的常量对象。

  4. 本地方法栈(Native JNI)引用的对象 C/C++ 本地方法通过 JNI 引用的 Java 对象。

  5. JVM 内部自带引用对象 Class 对象、常驻异常、系统类加载器。

  6. synchronized同步锁持有对象 正在执行同步代码块、持有锁的对象。

四、完整执行流程

  1. STW(Stop-The-World)暂停所有用户线程 必须冻结业务线程,防止遍历过程中对象引用被修改,保证引用链快照一致性。
  2. 标记 GC Roots,识别所有根对象。
  3. 深度 / 广度优先遍历对象图 从 GC Roots 出发,逐层标记所有直接、间接引用的存活对象(三色标记实现)。
  4. 遍历结束后
    • 被标记:存活,保留;
    • 未被标记(白色对象):不可达垃圾,后续执行清除。

五、底层实现:三色标记法

可达性分析遍历对象时,将对象分为 3 种颜色,简化标记逻辑、支持并发标记:

  1. 白色:初始状态,未扫描;遍历结束仍为白色 = 垃圾。
  2. 灰色 :已扫描到当前对象,但该对象内部引用的子对象还未全部扫描
  3. 黑色:当前对象已扫描,且它所有引用的子对象全部标记完成,完全存活。

遍历流程:GC Roots 先标记为灰色,循环取出灰色对象扫描,子对象变白→灰,父对象变黑色,直到无灰色对象。

六、优缺点

优点

  1. 彻底解决循环引用内存泄漏问题;
  2. 逻辑清晰,适配分代收集、CMS/G1/ZGC 等主流垃圾收集器。

缺点

  1. 基础标记阶段需要 STW,会造成业务线程停顿;
  2. 并发标记场景会出现漏标、多标问题(通过读写屏障解决)。

七、高频面试问答

1. 可达性分析与引用计数的核心区别?

  • 引用计数:靠计数器判断,无法处理循环引用,无 STW;
  • 可达性分析:靠 GC Roots 引用链判断,解决循环引用,基础标记阶段需要 STW。

2. 局部变量、静态变量为什么能作为 GC Roots?

局部变量存于虚拟机栈,线程执行时栈帧不会销毁;静态变量绑定类,类生命周期贯穿程序运行,二者天然是程序活跃引用,作为遍历起点。

3. 对象不可达后会立刻被回收吗?

不会。对象被判定不可达后,会进入两次标记流程:

  1. 第一次标记:筛选重写了finalize()方法的对象;
  2. 放入 F-Queue 队列,由低优先级线程执行finalize();若在 finalize 中重新建立 GC Roots 引用链,可自救存活;
  3. 第二次标记:finalize 执行完毕后,无引用链则真正回收。
相关推荐
IT爱学堂7 小时前
java版数据结构和算法+AI算法和技能学习指南
java·开发语言
民乐团扒谱机7 小时前
【微实验】倒谱算法(Cepstrum)深度解析:原理、数学推导与代码实现
人工智能·算法·语音识别
evans在进步7 小时前
LeetCode 394:字符串解码——Java 单栈模拟与嵌套解析详解
java·python·leetcode
Nil2088 小时前
leetcode 189轮转数组
数据结构·算法·leetcode
-dzk-8 小时前
【动态规划】LC 118.杨辉三角
算法·动态规划
恣逍信点8 小时前
《凌微经》静态自悖——变化之自因
人工智能·科技·算法·机器学习·业界资讯·拓扑学·哲学
m0_547486668 小时前
《Java程序设计与实践 》全套PPT课件2026
java·开发语言
吃着火锅x唱着歌8 小时前
LeetCode 3885.设计事件管理器
算法·leetcode·职场和发展
土司大王9 小时前
LeetCode hto100——字母异位词分组
java·算法·leetcode
Eloudy9 小时前
预词力:LLM 的唯一形式化能力
人工智能·算法·agent