一、概述
Java虚拟机在执行程序的过程会把它管理的内存划分为若干个不同的数据区。这些数据区有些是随着虚拟机进程的启动而一直存在的,有些区域则是依赖线程的启动和结束而创建和销毁的。
二、程序计数器
程序计数器可以看做是当前线程所执行的字节码的行号指示器,在Java虚拟机的概念模型中,字节码解释器工作时就是通过改变这个计数器的值来读取下一条需要执行的字节码指令。如果当前线程正在执行的是一个Java方法,这个计数器记录的值就是正在执行的字节码指令地址,如果是在执行本地方法,这个计数器的值为空(Undefined)。值得注意的是,这块区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域。
三、Java虚拟机栈
Java虚拟机栈就是我们常说的堆栈,这块区域也是线程私有的。虚拟机栈描述的是Java方法执行的线程内存模型:当一个方法被执行时,虚拟机栈会创建一个栈帧,这个栈帧储存了局部变量表、操作数栈、动态链接、方法返回地址等信息,当方法执行完成时,栈帧出栈。
局部变量表储存了编译时期可以确定的各种基本数据类型 ( boolean, byte, char, short, int, float)、对象引用(reference)和returnAddress类型(指向下一条字节码指令的地址)。这些数据类型在局部变量表中以局部变量槽(Slot)来表示,long和double类型会占用两个Slot。 局部变量表所需要的空间是在编译时就确定的,当调用一个方法时,这个方法需要多大的局部变量表空间是完全确定的。
在《Java虚拟机规范》中规定了这个区域的两种异常情况:
- If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
- If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
如果线程请求的虚拟机栈深度超过虚拟机所允许的深度,将抛出StackOverflowError异常。如果虚拟机栈容量动态扩展时申请不到足够的内存将抛出OutOfMemoryError异常。
注:Hotspot虚拟机的栈容量不可以动态扩展,不会因为动态扩展内存不足OOM,但线程申请栈空间时,如果内存不足,还是会OOM。