运行时数据区域
程序计数器
是一块较小的内存空间,可以看作是当前线程执行的字节码的行号指示器。
在虚拟机概念模型里,字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。
线程私有的内存,为了线程切换后能恢复到正确的位置,每条线程需要一个独立的程序计数器。
如果线程执行的是一个Java方法,记录的是正在执行的虚拟机字节码指令的地址;如果执行的是native方法,计数器为空(Undefined)。
Java虚拟机规范中唯一一个
没有规定任何OutOfMemoryError
的区域。
Java虚拟机栈
线程私有,生命周期与线程相同。
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈,动态链表,方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表存放了编译器可知的基本数据类型、对象引用、returnAddress类型。所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,再方法运行期间不会改变局部变量表的大小。
当线程请求的栈深度大于虚拟机所允许的深度(例如递归深度太深了),将抛出
StackOverflowError
。如果虚拟机栈允许动态扩展那当扩展到无法申请需要的内存时候则抛出OutOfMemoryError
。
本地方法栈
为虚拟机使用到的native方法服务。
本地方法栈区域与会抛出StackOverflowError
与OutOfMemoryError
。
Java堆
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。是Java虚拟机所管理的内存中最大的一块。
用于存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,也被称为“GC堆”。
Java堆可以处于物理上不连续的内存空间,只要逻辑上是连续的即可。
如果堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError
。
-Xmx
、-Xms
可设置堆的大小。
方法区
各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Non-Heap(
非堆
)
运行时常量池是方法区的一部分,存储编译器生成的各种字面量和符号引用、翻译出的直接引用。运行期间也可加入新的常量放入池中。例如String.intern()方法(返回常量池中字符串,如果常量池中存在,则直接返回常量池中该对象的引用;否则该对象加入常量池,然后返回引用)。
根据垃圾处理器的分代收集算法,永久代就在这里。当内存不足的时候将抛出
OutOfMemoryError
。