GC Roots 对象包括以下几种:(巧记:两栈两方法)
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中 JNI 引用的对象
虚拟机栈中引用的对象
虚拟机栈中引用的对象是指在 Java 程序中,方法中的局部变量所引用的对象。当一个方法被调用时,虚拟机会为该方法创建一个栈帧,栈帧中包含了该方法的局部变量表,其中存储了该方法中定义的所有局部变量及其引用的对象。
举个例子,假设有如下的 Java 代码:
public class Example {
public static void main(String[] args) {
int a = 1;
String b = "hello";
Object c = new Object();
// ...
}
}
在这个例子中,main
方法中定义了三个局部变量 a
、b
和 c
,其中 a
是一个基本数据类型,不是一个对象,因此不会被视为虚拟机栈中引用的对象。而 b
是一个 String
类型的对象,c
是一个 Object
类型的对象,它们都是虚拟机栈中引用的对象。
当 main
方法执行完毕后,虚拟机会将该方法的栈帧出栈,同时也会将其中的局部变量表中引用的对象释放掉,以便垃圾回收器回收这些对象所占用的内存空间。
本地方法栈中 JNI 引用的对象
本地方法栈中 JNI 引用的对象是指在 Java 程序中,使用 JNI(Java Native Interface)调用本地方法时所引用的对象。JNI 是一种机制,它允许 Java 程序调用本地方法,即使用 C 或 C++ 等语言编写的方法。
举个例子,假设如下的 Java 代码:
public class Example {
public static native void nativeMethod(Object obj);
// ...
}
在这个例子中,Example
类中定义了一个本地方法 nativeMethod
,它接受一个 Object
类型的参数。在本地方法中,可以使用 JNI 调用 C 或 C++ 等语言编写的方法,同时也可以将 Java 对象作为参数传递给本地方法。
当程序运行时,如果调用了 Example
类的 nativeMethod
方法,并将一个 Java 对象作为参数传递给该方法,那么这个 Java 对象就会被视为本地方法栈中 JNI 引用的对象。
当本地方法执行完毕后,虚拟机会将本地方法栈出栈,同时也会将其中引用的对象释放掉,以便垃圾回收器回收这些对象所占用的内存空间。
方法区中类静态属性引用的对象
方法区中类静态属性引用的对象是指在 Java 程序中,类的静态属性所引用的对象。静态属性是指在类中使用 static
关键字修饰的属性,它属于类本身而不是类的实例,因此在程序运行期间只会被创建一次。
举个例子,假设如下的 Java 代码:
public class Example {
private static String message = "hello";
// ...
}
在这个例子中,Example
类中定义了一个静态属性 message
,它是一个 String
类型的对象,因此它是方法区中类静态属性引用的对象。
当程序运行时,虚拟机会为 Example
类创建一个类对象,并将其中的静态属性 message
初始化为 "hello"
。在程序运行期间,如果其他代码中引用了 Example
类的静态属性 message
,那么这个静态属性所引用的对象就会被视为方法区中类静态属性引用的对象。
当程序结束时,虚拟机会将 Example
类的类对象和其中的静态属性释放掉,以便垃圾回收器回收这些对象所占用的内存空间。
方法区中常量引用的对象
方法区中常量引用的对象是指在 Java 程序中,使用 final
关键字定义的常量所引用的对象。常量是指在程序运行期间不可变的值,一旦被初始化后就不能再被修改。
举个例子,假设如下的 Java 代码:
public class Example {
private static final String MESSAGE = "hello";
// ...
}
在这个例子中,Example
类中定义了一个常量 MESSAGE
,它是一个 String
类型的对象,因此它是方法区中常量引用的对象。
当程序运行时,虚拟机会为 Example
类创建一个类对象,并将其中的常量 MESSAGE
初始化为 "hello"
。在程序运行期间,如果其他代码中引用了 Example
类的常量 MESSAGE
,那么这个常量所引用的对象就会被视为方法区中常量引用的对象。
当程序结束时,虚拟机会将 Example
类的类对象和其中的常量释放掉,以便垃圾回收器回收这些对象所占用的内存空间。由于常量是不可变的,因此它们所引用的对象也不会被修改,因此在程序运行期间它们所引用的对象一直都是相同的。