Java中的可达性分析(Reachability Analysis)是垃圾收集器用来判断对象是否存活的一种算法。其核心思想是通过一系列称为“GC Roots”的对象作为起点,跟踪引用链,如果一个对象到GC Roots没有任何引用链,则认为此对象是不可达的,即可回收的。

GC Roots包括:

  1. 本地变量表中引用的对象,即当前激活线程的局部变量。

  2. 方法区中类静态属性引用的对象,如Java类的引用类型静态变量。

  3. 方法区中常量引用的对象,如字符串常量池里的引用。

  4. 本地方法栈中JNI(即通常所说的Native方法)引用的对象。

可达性分析过程:

  1. 标记阶段:从所有GC Roots开始,遍历这些节点所引用的对象,然后是这些对象引用的对象,依此类推。每访问一个对象,就将其标记为活动对象,这个过程是递归的。

  2. 停止-复制(Stop-and-Copy)或 标记-清除(Mark-and-Sweep):在标记完成后,未被标记的对象会被垃圾回收器回收。具体采取哪种回收策略,取决于回收器的类型和内存情况。

  3. 可达性的级别
    • 可直接访问:从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的一部分。

可达性分析的运行原理确保了只有那些不再被任何线程、静态引用等所使用的对象才会被垃圾回收,而这样的判定是通过一系列的对象引用链来实现的。这也意味着,循环引用的对象,如果没有任何外部引用指向它们的引用链,同样会被回收。

本篇文章来源于微信公众号: 互联网面试小帮手



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2024-04-22