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

一、定义

可达性分析(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 执行完毕后,无引用链则真正回收。
相关推荐
nice_lcj5208 小时前
【从零理解 Spring AI · 03】Spring AI 在 Spring 生态里的位置
java·spring boot·大模型·spring ai·ai应用开发
码农小河6618 小时前
基于SSM+JSP的高校专业信息管理系统【附源码+数据库】
java·开发语言·数据库
其实防守也摸鱼20 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
风若飞20 小时前
Spring Ai 入门遇到问题1
java·后端·spring
Nuanyt21 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
黑马程序员毕设21 小时前
基于 Java 的餐饮点餐系统设计与应用报告
java·开发语言
SL_staff21 小时前
从文档工具到知识中枢:基于JVS数字底座构建企业级统一内容管理平台的技术实践
java·开源·全栈
SL_staff21 小时前
从‘连得上’到‘管得好’:JVS-IOT双引擎驱动设备运维闭环
java·物联网·产品
w_zero_one1 天前
递归算法(一)
java·开发语言·算法