运行时数据区有哪些区域?它们的作用分别是什么?

135 阅读3分钟

Java虚拟机运行时数据区.jpg

程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,用来记录当前线程正在执行的字节码指令的地址。

当线程执行本地方法的时候,存储的值为undefined。

方法区(Method Area)

方法区存储每一个类的结构信息,例如运行时常量池(runtime constant pool)、变量和方法数据、构造函数和普通方法字节码内容,以及一些类、实例、接口初始化时需要用到的特殊方法。

运行时常量池

运行时常量池是class文件中每一个类或接口的常量池表(constant_pool table)的运行时表现形式。它包含了若干种不同的常量,从编译期间可知的数值字面量到必须在运行期间解析后才能获得的方法或字段引用。

Java虚拟机栈(Java VM Stack)

Java虚拟机用来存储栈帧(Frame)。

一个方法从调用到返回的过程就是一个栈帧从入栈到出栈的过程。

栈帧

栈帧是用来存储数据和部分过程结果的数据结构,同时也用来处理动态链接(dynamci linking)、方法返回值和异常分派(dispatch exception)。

每一个栈帧都有自己的局部变量表、操作数栈和一个指向当前方法所属类的运行时常量池的引用。

局部变量表

每个栈帧都包含一组被称为局部变量表的变量列表。

一个局部变量可以保存一个类型为boolean、byte、char、short、int、float、referenc或returnAddress的数据。

两个局部变量可以保存一个类型为long或double的数据。

Java虚拟机使用局部变量表来完成方法调用时的参数传递。当调用类方法的时候,它的参数会依次传递到从0开始的连续位置。当调用实例方法的时候,第0个局部变量一定用来存储该实例方法所在对象的引用(即Java语言中的this关键字),后续的其他参数传递到局部变量表中从1开始的连续位置。

动态链接

每个栈帧都包含一个指向当前方法所在类的运行时常量的引用,以便对当前方法的代码实现动态链接。

在class文件中,一个方法若要调用其他方法,或者访问其他变量,需要使用符号引用(symbolic reference)来表示,动态链接的作用就是将这些以符号引用表示的方法转换成对实际方法的引用。

本地方法栈(Native Method Stack)

本地方法栈用来支持本地方法的执行。

Java堆(Heap)

《Java虚拟机规范》对Java堆的描述是:Java堆是所有类实例和数组对象分配内存的区域。

《深入理解Java虚拟机:JVM高级特性与最佳实践》中描述:“几乎 “所有对象的实例都在这里分配内存。

这是因为从实现角度来看,随着即时编译技术的进步,栈上分配、标量替换等优化手段使得所有对象都在堆上分配不那么绝对了。

直接内存(Dicrect Memory)

本地内存不是运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域,但是这部分内存也被频繁使用。

在JDK1.4中新引入了NIO类,引入了一个基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配内存,然后通过一个存储在Java堆中里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能够避免在Java堆和Native堆中来回复制数据,从而提升性能。