为了解决引用计数法无法解决循环引用的问题,在Java中采取了 可达性分析法

    该方法的基本思想是吧对象之间的赋值引用看作是成一个引用链,这些引用链的头部被称为GC Roots ,发生垃圾收集是,通过一系列的“GC Roots”对象作为起点进行搜索所有引用链,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的

    不过要注意的是被判定为不可达的对象不一定就会成为可回收对象

    被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。

    image.png

    说到GC roots(GC根),在JAVA语言中,可以当做GC roots的对象有以下几种:

    1. 虚拟机栈中的引用对象(方法的本地变量)
    2. 方法区中的类静态属性引用的对象
    3. 方法区中的常量引用的对象(声明为final的常量值)
    4. 本地方法栈中JNI的引用对象(方法的本地变量)

    那么,可达性分析有没有问题(缺点)呢?

    消耗大量时间
    从前面可达性分析知道,GC Roots主要在全局性的引用(常量或静态属性)和执行上下文中(栈帧中的本地变量表);
    要在这些大量的数据中,逐个检查引用,会消耗很多时间;

    GC停顿
    可达性分析期间需要保证整个执行系统的一致性,对象的引用关系不能发生变化;
    导致GC进行时必须停顿所有Java执行线程 (称为 “Stop The World” );
    (几乎不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的)

    Stop The World:
    是JVM在后台自动发起和自动完成的;
    在用户不可见的情况下,把用户正常的工作线程全部停掉;

    耗时和GC停顿
    由于需要从GC Roots开始逐个检查引用,所以耗时是缺点之一,而且在此期间,需要保证整个执行系统的一致性,对象的引用关系不能发生变化,所以会导致GC进行时必须停顿所有Java执行线程(STW),所以这是缺点之二。
    注:几乎不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的。