7 JVM运行时内存区域
JVM运行时内存区域主要包括五块:程序计数器、java虚拟机栈、本地方法栈、方法区、堆
上述五块区域也可以分为线程共享和线程不共享两部分
线程共享区域:
-
方法区
方法区是存放基础信息的位置,主要包括三部分:
-
类的元信息
保存了所有类的基本信息
-
运行时常量池
保存了字节码文件中的常量池内容
-
字符串常量池(JDK8将字符串常量池移动到了堆中)
保存了字符串常量
-
-
堆
- 一般Java程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上
- 栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享
- 堆空间有三个需要关注的值,
used
(表示当前已使用的堆内存)、total
(java虚拟机已经分配的可用堆内存)、max
(表示Java虚拟机可用分配的最大堆内存)
线程不共享区域:
-
程序计数器
程序计数器(Program Counter Register)也叫PC寄存器,每个线程会通过程序计数器记录当前要执行的的字节码指令的地址
-
java虚拟机栈
Java虚拟机栈 (Java Virtual Machine Stack)采用栈的数据结构来管理方法调用中的基本数据,先进后出 (First in Last Out),每一个方法的调用使用一个栈帧(Stack Frame)来保存(栈帧保存了方法的基本信息)
- 栈帧的组成
-
局部变量表,局部变量表的作用是在运行过程中存放所有的局部变量
-
栈帧中的局部变量表是一个数组,数组中每一个位置称之为槽(slot),
long
和double
类型占用两个槽,其他类型占用一个槽 -
方法参数也会保存在局部变量表中,其顺序与方法中参数定义的顺序一致
-
局部变量表保存的内容有:实例方法的this对象,方法的参数,方法体中声明的局部变量
-
为了节省空间,局部变量表中的槽是可以复用的,一旦某个局部变量不再生效,当前槽就可以再次被使用
-
-
操作数栈,操作数栈是栈帧中虚拟机在执行指令过程中用来存放临时数据的一块区域
-
帧数据,帧数据主要包含动态链接、方法出口、异常表的引用
- 动态链接保存的是虚拟地址与运行时常量池的物理地址的映射关系
- 方法出口指的是方法在正确或者异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以在当前栈帧中,需要存储此方法出口的地址
- 异常表存放的是代码中异常的处理信息,包含了try代码块和catch代码块执行后跳转到的字节码指令位置。
- 动态链接保存的是虚拟地址与运行时常量池的物理地址的映射关系
-
Java虚拟机栈-栈内存溢出
- Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出
- Java虚拟机栈内存溢出时会出现StackOverflowError的错误
- Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出
-
本地方法栈
- Java虚拟机栈存储了Java方法调用时的栈帧,而本地方法栈存储的是
native
本地方法的栈帧 - 在Hotspot虚拟机中,Java虚拟机栈和本地方法栈实现上使用了同一个栈空间。本地方法栈会在栈内存上生成一个栈帧,临时保存方法的参数同时方便出现异常时也把本地方法的栈信息打印出来
- Java虚拟机栈存储了Java方法调用时的栈帧,而本地方法栈存储的是