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

一、定义

可达性分析(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 执行完毕后,无引用链则真正回收。
相关推荐
笨笨饿1 小时前
#102_Codex无在VSCold无法打开
java·c语言·数据库·笔记
paeamecium1 小时前
【PAT甲级真题】- Kuchiguse (20)
数据结构·c++·python·算法·pat考试·pat
程序员清风1 小时前
AI不是万能的,大家要专注实践!
java·后端·面试
青山木1 小时前
Hot 100 --- 全排列
java·数据结构·算法·leetcode·深度优先
海兰1 小时前
【高速缓存】RedisVL 存储类型选择指南:Hash 与 JSON
人工智能·redis·算法·缓存·json·哈希算法
KaMeidebaby1 小时前
卡梅德生物技术快报|核酸适配体文库筛选:核酸适配体文库筛选全流程技术解析:NGS与AI辅助方案的设计与实践
前端·人工智能·物联网·算法·百度
猫猫不是喵喵.1 小时前
认证授权【Spring Security】
java·认证授权
小罗水1 小时前
第1章 大模型、企业知识库与 RAG 平台概述
java·spring
不知疲倦的仄仄1 小时前
MySQL/Read View快照/MVCC/串行化
java·数据库·mysql