共享区
在JVM中,共享区主要是指那些可以被多个线程共同访问的内存区域。主要包括:
-
方法区(Method Area):
- 用来存储加载的类信息、常量、静态变量、编译后的代码等数据。
- 在HotSpot虚拟机中,JDK 8及之前版本使用永久代(PermGen space)实现方法区,JDK 8及之后版本使用元空间(Metaspace)来实现。
- 方法区是线程共享的,随着JVM的启动而创建,随着JVM的关闭而销毁。
-
堆内存(Heap):
- JVM启动时创建,用于存放对象的实例。
- 堆内存也是线程共享的,垃圾回收器主要管理堆内存。
- 堆内存可以细分为老年代(Old Generation)和新生代(Young Generation),新生代又可以进一步细分为Eden区、From Survivor区和To Survivor区。
GC Root
GC Root是垃圾回收器进行垃圾收集时,需要判断哪些对象还“存活”的起点。
如果一个对象到GC Root没有任何引用链,那么该对象就可以被垃圾回收器回收。
GC Root主要包括以下几种:
-
虚拟机栈(Java Stack)中引用的对象:
- 栈帧中的局部变量表引用的对象。
- 示例代码:
public class Test { public static void main(String[] args) { Test a = new Test(); // a 是局部变量,此时a是GC Root a = null; // a与原来指向的对象断开连接,对象等待GC回收 } }
-
方法区中的类静态属性引用的对象:
- 类的静态属性引用的对象。
- 示例代码:
public class Test { public static Test s = new Test(); // s是类静态属性,此时s是GC Root }
-
方法区中常量引用的对象:
- 常量引用的对象。
- 示例代码:
public class Test { public static final Test CONSTANT = new Test(); // CONSTANT是常量,此时CONSTANT是GC Root }
-
本地方法栈(Native Method Stack)中JNI(Native方法)引用的对象:
- 通过JNI调用的本地方法引用的对象。
- 示例代码(JNI调用部分通常用C或C++编写,这里仅展示Java调用本地方法的声明):
public class Test { // 声明本地方法 public native void nativeMethod(); // 在某个地方调用nativeMethod public static void main(String[] args) { Test test = new Test(); test.nativeMethod(); // 假设nativeMethod内部引用了某些对象,这些对象在nativeMethod执行期间是GC Root } }
小结
| 类型 | 描述 | 示例代码片段 | |
|---|---|---|---|
| 共享区 | 方法区 | 存储类信息、常量、静态变量等 | - |
| 堆内存 | 存放对象实例,垃圾回收器主要管理区域 | - | |
| GC Root | 虚拟机栈中引用的对象 | Test a = new Test(); | |
| 方法区中类静态属性引用的对象 | public static Test s = new Test(); | ||
| 方法区中常量引用的对象 | public static final Test CONSTANT = new Test(); | ||
| 本地方法栈中JNI引用的对象 | public native void nativeMethod();(本地方法内部引用) |
注意:由于本地方法栈中的JNI引用通常涉及到本地代码(如C或C++),因此在Java代码中直接展示其作为GC Root的示例可能不够直观。
在实际应用中,当Java通过JNI调用本地方法时,如果本地方法内部引用了Java对象,那么这些对象在本地方法执行期间就可以被视为GC Root。
欢迎访问我的(夏壹分享)公众号 和 博客(sanzhishu)后缀top