问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

什么是GC Roots?一文详解JVM垃圾回收机制的关键概念

创作时间:
作者:
@小白创作中心

什么是GC Roots?一文详解JVM垃圾回收机制的关键概念

引用
CSDN
1.
https://blog.csdn.net/m0_63653444/article/details/140323721

在Java虚拟机(JVM)中,垃圾回收(Garbage Collection,简称GC)是一个核心机制,用于自动管理内存,释放不再使用的对象所占用的空间。但是,JVM是如何判断哪些对象应该被回收,哪些应该保留呢?这就要从GC Roots的概念说起。

GC Roots的定义

GC Roots可以类比为"诛九族"中的共同祖先。在堆的垃圾回收中,JVM会追踪对象的祖先引用。如果这些祖先已经不再存在,它们将被清理掉。那些能够逃过垃圾回收的祖先非常特殊,它们被称为GC Roots。

GC Roots的作用

通过从GC Roots开始向下追溯和搜索,形成一个称为"Reference Chain"(引用链)的链条。当一个对象无法与任何GC Root建立关联时,它将被无情地清除。例如,在下图中,Obj5、Obj6、Obj7由于无法与GC Roots关联,将在垃圾回收时被销毁。

垃圾回收就是围绕着GC Roots去做的。同时,它也是很多内存泄露的根源,因为其他引用根本没有这样的权利。

GC Roots的类型

GC Roots是一组必须活跃的引用。用通俗的话来说,就是程序接下来通过直接引用或者间接引用,能够访问到的潜在被使用的对象。GC Roots主要包括以下四种类型:

  1. 虚拟机栈中引用的对象

当一个对象在虚拟机栈(栈帧中的本地变量表)中被引用时,它充当了GC Root的作用。例如:

public class Example {
    public static void main(String[] args) {
        Example obj = new Example(); // obj 是 GC Root
        obj = null; // 断开 obj 对原对象的引用
    }
}

在上面的示例中,obj是虚拟机栈中的本地变量,当obj被赋值为null时,原对象与GC Root断开连接,因此原对象会被回收。

  1. 方法区中类静态属性引用的对象

类静态属性引用的对象也是GC Roots。例如:

public class Example {
    public static Example s; // 类静态属性引用的对象
    public static void main(String[] args) {
        Example obj = new Example();
        obj.s = new Example(); // s 是 GC Root
        obj = null; // 断开 obj 对原对象的引用
    }
}

在上面的示例中,当栈帧中的本地变量obj = null时,由于obj原来指向的对象与GC Root(变量obj)断开了连接,所以obj原来指向的对象会被回收,而由于我们给s赋值了变量的引用,s在此时是类静态属性引用,充当了GC Root的作用,它指向的对象依然存活。

  1. 方法区中常量引用的对象

常量引用的对象也不会因为其他引用断开而被回收。例如:

public class Example {
    public static final Example CONSTANT = new Example(); // 常量引用的对象
    public static void main(String[] args) {
        Example obj = new Example();
        obj = null; // 断开 obj 对原对象的引用,但 CONSTANT 不受影响
    }
}

在上面的示例中,常量CONSTANT指向的对象不会因为obj的断开而被回收。

  1. 本地方法栈中JNI引用的对象

JNI(Java Native Interface)是Java调用非Java代码的接口,本地方法栈中JNI引用的对象也是GC Roots。例如:

JNIEXPORT void JNICALL Java_com_pecuyu_jnirefdemo_MainActivity_newStringNative(JNIEnv *env, jobject instance,jstring jmsg) {
...
   // 缓存String的class
   jclass jc = (*env)->FindClass(env, STRING_PATH);
}

注意事项

  1. 我们这里说的是活跃的引用,而不是对象,对象是不能作为GC Roots的。
  2. GC过程是找出所有活对象,并把其余空间认定为"无用";而不是找出所有死掉的对象,并回收它们占用的空间。所以,哪怕JVM的堆非常的大,基于tracing的GC方式,回收速度也会非常快。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号