《深入理解Java虚拟机》第2章总结

Java运行时数据区域

程序计数区:线程私有,当前线程所执行字节码的行号指示器。

虚拟机栈:线程私有,用于虚拟机执行Java方法(字节码),每个方法执行都会同步创建1个栈帧。

本地方法栈:线程私有,用于虚拟机执行本地(Native)方法。

堆:线程共享,存放对象实例,垃圾回收器管理的内存区域。

方法区:线程共享,存储被虚拟机加载的类型信息、常量、静态变量等数据。

1. 程序计数区

线程私有,当前线程所执行字节码的行号指示器。

字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

不会抛出OutofMemoryError异常。

2. 虚拟机栈

线程私有,生命周期和线程相同。

用于虚拟机执行Java方法(字节码),每个方法从调用到执行完毕,就对应1个栈帧在虚拟机栈的入栈和出栈。

会抛出OutofMemoryError异常以及StackOverflowError异常。

2.1 局部变量表

我们通常关注虚拟机栈中局部变量表部分。

存放编译器可知的各种基本数据类型、对象引用和returnAddress类型。

// 代码片段1
public void test(){
int i = 3;
Person p = new Person();
int[] nums = {1,2,3};
}

复制代码

上述代码片段1中i, p, nums都存在局部变量表中。

3. 本地方法栈

线程私有,生命周期和线程相同。

用于虚拟机执行本地(Native)方法。

会抛出OutofMemoryError异常以及StackOverflowError异常。

4. 堆

线程共享的内存区域,在虚拟机启动时创建。

唯一的目的是存放对象实例。代码片段1中new Person()所得的对象实例以及数组值{1,2,3}都存在堆中。

会抛出OutofMemoryError异常。

5. 方法区

线程共享,存储被虚拟机加载的类型信息、常量、静态变量等数据。

会抛出OutofMemoryError异常。

Java 8之前方法区的数据存在堆的永久代,Java 8开始去掉了永久代,方法区的数据存储在元空间(Meta Space)

5.1 运行时常量池

Class文件中的常量池表(存放编译器生成的各种字面量和符号引用)经过类加载后就存放在方法区的运行时常量池中。

相比Class文件的常量池,运行时常量池具有动态性。即运行期间也可以有常量进入运行时常量池,比如String类的intern()方法。