Java内存区域与相关异常

java程序运行时内存由虚拟机进行分配管理,其管理的运行时数据区域有以下几个部分:

  1. 程序计数器
    一块较小的内存空间,用于指示当前字节码执行地址记录,可在程序中断后切回到正确的位置以继续执行。若执行的是非java方法,而是Native方法,则值为空。该区域是java虚拟机规范中唯一一个没有规定任何OutOfMemoryError异常的区域。

  2. Java虚拟机栈
    线程私有,与线程生命周期相同。此内存区域存储着局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表存放了各种基本数据类型、对象引用、指向字节码指令的地址;它所需要的内存空间,在编译期间是确定的,并在编译时完成分配。在java虚拟机规范中,如果线程请求的栈深度大于虚拟机的允许的深度,将抛出StackOverflowError异常,如果虚拟机栈可动态扩展,但申请不到足够内存,将抛出OutOfMemoryError异常。

  3. 本地方法栈
    本地方法栈与java虚拟机栈作用相同,抛出的异常相同。区别在于本地方法栈用于为Native方法服务。

  4. Java堆
    大多数情况下,该段内存是java虚拟机管理的最大一块内存,几乎程序的所有对象实例及数组都在此处分配内存,因此它也是GC的重点关注区域。java堆由所有的线程共享,在内存用尽且无法扩展的时候,将抛出OutOfMemoryError异常,其大小可通过-Xmx 和 -Xms控制。

  5. 方法区
    该区域同样被所有线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。此区域的垃圾回收发生较少,且回收效果没有java堆那样明显(其主要针对常量池回收和类型卸载),内存分配无法满足时将抛出OutOfMemoryError异常。

  6. 运行时常量池
    属于方法区的一部分,编译器生成的各种字面量和符号引用在类加载后进入方法区常量池存放。运行时常量池相较于class常量池的一个重要特征是具备动态性,常量可以在运行时放入该区域。该区域内存受方法区内存限制,不足时抛出OutOfMemoryError异常。

关于非RAM存储的数据
如果数据存活于程序之外,则它们可以与程序脱离而存在,如流对象持久化对象。流对象通常通过字节流的方式,将对象进行传输,持久化对象则可将对象存放在磁盘上。


基本类型存储空间分配

基本类型 大小 包装器类型
boolean - Boolean
char 16-bit Character
byte 8 bits Byte
short 16 bits Short
int 32 bits Integer
long 64 bits Long
float 32 bits Float
double 64 bits Double