运行时数据区域
Java虚拟机在执行Java程序的过程汇总会把它管理的内存划分成若干个不同的数据区域。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域
程序计数器
又名程序寄存器,PC Register
线程私有
是一块较小的内存
在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
如果一个Java程序正在执行Native方法,这个计数器的值应该为空(Undefined)
虚拟机栈
JVM Stacks
线程私有
它的生命周期和线程相同。每启动一个线程,JVM都会为它分配一个Java虚拟机栈
虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
本地方法栈是为虚拟机使用到的Native 方法服务。
用于存放方法中的局部变量表,操作数栈,动态连接,方法出口等
局部变量表
存放了编译器可知的JVM基本数据类型、对象引用(reference类型)、returnAddress类型(指向了下一条字节码指令的地址)。局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的数据占两个变量槽(long和double),其余占一个变量槽。一个变量槽占多大的空间是由不同的JVM自己来决定的。
操作数栈
也常被称为操作栈。操作数栈的每一个元素可以是任意Java数据类型,32位的数据类型占用一个栈容量,64位的栈两个栈容量。在方法执行的过程中,根据字节码指令,往操作数栈中写入或提取数据。主要保存计算过程中的中间结果。
动态连接
也叫指向运行时常量池的方法引用,动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。
方法出口
当一个方法执行是有两种方法退出该方法:正常完成出口,异常完成出口。无论采用何种方法退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行。
本地方法栈
Native Method Stack
线程私有
为虚拟机使用到的Native方法服务。如Java使用C++接口时,代码在此区运行。
堆
Heap
线程共享
在Java世界里“几乎”所有对象实例都会在这里分配内存。(随着Java语言的发展,现在已经能看到出现值类型的支持,栈上分配已经在悄然发生)
在《Java虚拟机规范》规定,Java堆可以是处于物理上不连续的内存空间,但在逻辑上他应该被视为连续的。
存放静态变量,数组,对象
Java程序在运行时创建的所有类型对象和数组都存储在堆中。JVM会根据new指令在堆中开辟一个确定类型的对象内存空间。但是堆中开辟对象的空间并没有任何人工指令可以回收,而是通过JVM的垃圾回收器负责回收。
其中一个对象的引用可能在整个运行时数据区中的很多地方存在,比如Java栈,堆,方法区等。
堆中对象还应该关联一个对象的锁数据信息以及线程的等待集合(线程等待池)。这些都是实现Java线程同步机制的基础。
方法区
Method Area
线程共享
用于存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译器遍以后的代码缓存等数据。
在《Java虚拟机规范》中把方法区描述为堆的一个逻辑部分,但它有一个别名叫“非堆(Non-Heap)”,目的是与Java堆区分开来。
常量池
常量池是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表,常量表用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
资料来源:《深入理解Java虚拟机》