gc roots是可达性分析的起点,包括虚拟机栈局部变量、本地方法栈jni引用、方法区静态字段与常量引用;仅强引用链决定对象存活,循环引用不影响回收。

Java 垃圾回收通过可达性分析算法判断对象是否存活:从一组称为“GC Roots”的对象出发,沿着引用链向下搜索,所有能被访问到的对象视为存活,其余不可达对象则被标记为可回收。
哪些对象可以作为 GC Roots?
GC Roots 是可达性分析的起点,必须是确定不会被回收的活跃对象。主要包括:
- 虚拟机栈(栈帧中的局部变量表)中引用的对象
- 本地方法栈中 JNI(即 Native 方法)引用的对象
- 方法区中类静态属性引用的对象(如 public static Object obj)
- 方法区中常量引用的对象(如字符串常量池里的字符串)
- Java 虚拟机内部的特殊对象,如基本类型的 Class 对象、系统类加载器、同步锁(monitor)持有的对象等
引用链如何影响可达性?
可达性依赖强引用链**的连通性**。只要存在一条由强引用构成的路径从 GC Roots 到目标对象,该对象就不可回收:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 例如:A → B → C,其中 A 是局部变量(GC Root),B 是 A 的成员变量,C 是 B 的成员变量,则 C 可达
- 若 A 被置为 null,且无其他引用指向 B,则 B 和 C 同时变为不可达
- 软引用、弱引用、虚引用不参与可达性判定——它们不影响对象是否“存活”,只影响 GC 时的回收优先级和时机
两次标记与 finalize 的作用(已过时但需理解逻辑)
在早期 JDK(如 8 及之前),若对象在第一次标记时发现没有可达路径,会进入“即将回收”队列,并尝试调用其 finalize() 方法(前提是重写了且未执行过)。第二次标记时,若对象在 finalize() 中重新与 GC Roots 建立了强引用(如把自己赋值给某个静态变量),则会被移出回收队列。
- JDK 9 开始 finalize() 被标记为 @Deprecated,JDK 18 正式移除
- 现代 JVM(如 ZGC、Shenandoah)不依赖该机制,对象一旦不可达即判定为可回收
- 实际开发中应避免依赖 finalize(),改用 Cleaner 或显式资源管理(try-with-resources)
注意:循环引用不导致内存泄漏
Java 不使用引用计数,因此两个对象互相引用但无外部引用时(如 A.ref = B; B.ref = A;),只要它们都不被 GC Roots 直接或间接引用,就会被正常回收。
- 这与 Python 等使用引用计数的语言有本质区别
- 可达性分析天然解决循环引用问题,无需额外处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










