Java中的可达性分析(Reachability Analysis)是垃圾收集器用来判断对象是否存活的一种算法。其核心思想是通过一系列称为“GC Roots”的对象作为起点,跟踪引用链,如果一个对象到GC Roots没有任何引用链,则认为此对象是不可达的,即可回收的。
GC Roots包括:
-
本地变量表中引用的对象,即当前激活线程的局部变量。
-
方法区中类静态属性引用的对象,如Java类的引用类型静态变量。
-
方法区中常量引用的对象,如字符串常量池里的引用。
-
本地方法栈中JNI(即通常所说的Native方法)引用的对象。
可达性分析过程:
-
标记阶段:从所有GC Roots开始,遍历这些节点所引用的对象,然后是这些对象引用的对象,依此类推。每访问一个对象,就将其标记为活动对象,这个过程是递归的。
-
停止-复制(Stop-and-Copy)或 标记-清除(Mark-and-Sweep):在标记完成后,未被标记的对象会被垃圾回收器回收。具体采取哪种回收策略,取决于回收器的类型和内存情况。
-
可达性的级别: -
可直接访问:从GC Roots直接引用的对象。
-
间接可访问:通过一系列的引用链可以从GC Roots到达的对象。
-
不可访问:GC Roots无法到达的对象。

例子详解:
考虑以下Java代码片段:
public class GCRootsExample {private static GCRootsExample staticVariable;public void gcRootsTestMethod() {GCRootsExample localVariable = new GCRootsExample();System.gc(); // 第1次GC调用// 更多操作...}public static void main(String[] args) {GCRootsExample gcre = new GCRootsExample();gcre.gcRootsTestMethod();System.gc(); // 第2次GC调用// 更多操作...}}
在上述代码中:
-
第1次GC调用: 在
gcRootsTestMethod方法执行期间,localVariable是一个活动的本地变量,并且它指向一个GCRootsExample实例。因此,在第1次调用System.gc()时,由localVariable引用的GCRootsExample对象是不会被回收的,它通过localVariable与GC Roots相连。 -
方法返回后,假设我们又回到了
main方法,并且没有其他对localVariable的引用,那么localVariable引用的GCRootsExample对象现在已经不再有任何本地变量表中的引用。此时localVariable超出了作用域,该对象变得不可访问了。 -
第2次GC调用: 在
main方法中,尽管我们创建了一个GCRootsExample实例gcre,但是在调用完gcRootsTestMethod之后,并没有对gcre进行任何操作,也没有再传递引用。如果main方法之后没有对gcre的引用(即使它是一个静态变量),则gcre可能被视为垃圾并被收集。然而,如果staticVariable仍然保持着对某个GCRootsExample实例的引用,那么这个实例将不会被回收,因为静态变量是GC Roots的一部分。
可达性分析的运行原理确保了只有那些不再被任何线程、静态引用等所使用的对象才会被垃圾回收,而这样的判定是通过一系列的对象引用链来实现的。这也意味着,循环引用的对象,如果没有任何外部引用指向它们的引用链,同样会被回收。
本篇文章来源于微信公众号: 互联网面试小帮手
微信扫描下方的二维码阅读本文


Comments NOTHING