Java运行时数据区域
Java虚拟机所管理的内存包括以下几个运行时数据区域,如下图:
程序计数器
程序计数器(Program Counter Register)是一块较小的内存区域,是当前线程执行的字节码的行号指示器。程序计数器是一块私有的内存区域,每个线程都有一个独立的程序计数器。如果线程正在执行的是一个Java方法,这个程序计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。程序计数器所在的内存区域是唯一一个在Java虚拟机没有OOM(OutOfMemoryError)情况的区域。
Java虚拟机栈
Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,生命周期与线程同步。虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
虚拟机栈内存区域会出现两种异常:
1.当线程请求的栈深度大于虚拟机允许的深度,会抛出StackOverflowError异常;
2.当改区域需要扩展时申请不到足够的内存,就会抛出OOM(OutOfMemoryErro)异常。
本地方法栈
本地方法栈(Native Method Stack)也是线程私有的。本地方法栈与虚拟机栈的作用相似,它们的区别是虚拟机栈执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。异常跟虚拟机栈一样有两个。
上面三个内存数据区域(程序计数器、Java虚拟机栈、本地方法栈)都是私有的,那么我们来看一下内存线程共享的数据区域。
Java堆
Java堆是所有线程共享的一个内存区域,在虚拟机启动时创建。主要是存放对象实例(并不是全部对象实例)和数组,因此Java堆是GC收集器管理的主要区域。Java堆可以是处于物理上不连续的内存空间中,只要逻辑上是联系的。通过-Xmx和-Xms控制堆的内存大小,当给对象实例分配内存的时出现对内存不足并且无法申请到更多的内存情况会抛出OOM异常。
方法区
方法区(Method Area)与Java堆一样是线程之间共享的内存区域。他主要存储被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。该区域也是人们常说的“永久代”,但是也会被GC回收,该区域的内存回收主要是针对常量池的回收和对类的卸载。当方法区无法满足内存分配时也会抛出OOM异常。