注:图中线程隔离意味着线程私有。
程序计数器(Program Counter Register)
- 是一块较小的内存空间。
- 可以看做是当前线程所执行字节码的行号指示器。(字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理,线程恢复都需要依赖这个计数器)。
- 每个线程都需要有一个独立的程序计数器,各条线程之间互不影响,独立存储,是线程私有内存。
- 唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError异常情况的区域。
java虚拟机栈(Java Virtual Machine Stacks)
- 线程私有,生命周期与线程相同。
- 虚拟机栈描述的是java方法执行的内存模型,每个方法执行时都会创建一个栈帧(stack frame,用于存储局部变量表,操作数栈、动态链接等信息),每个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈出栈的过程(压栈运行)。
- 如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出StackOverflowError;如果虚拟机栈可以动态扩展,扩展时无法申请到足够的内存 就会抛出 OutOfMemeryError。
本地方法栈(Native Method Stack)
- 类似于上一个java虚拟机栈,区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。
- 和虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError,OutOfMemeryError。
java堆(Java Heap)
- 内存最大的一块,被所有线程共享,在虚拟机启动时创建。
- 所有对象实例以及数组都要在堆上分配(非“绝对”说法)。
- Java堆是垃圾收集器管理的主要内存区域,因此很多时候也被称作“GC堆”(Garbage Collected Heap)。
- 如果在堆中没有内存完成实例分配,并且无法扩展时,将会抛出OutOfMemeryError。
方法区(Method Area)
- 线程共享区域,用于存储已被虚拟机加载的类信息、常亮、静态变量等。
- 方法区!= 永久代,但是相对Java堆而言,垃圾收集行为在这个区域比较少。
- 无法满足内存分配需求时看,抛OutOfMemeryError异常。
运行时常量池
- 方法区的一部分。
- 存放编译期生成的各种字面量和符号引用。
- 受方法区内存限制,常量池在无法申请到内存时会抛出OutOfMemeryError异常。
直接内存
- 不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,简单来说 是 堆外内存
- 不受Java堆大小限制,但是 受到本机总内存 限制 ,当各个区域内存总和加上直接内存 大于 物理内存时,会抛出OutOfMemeryError 异常
参考《深入理解java虚拟机》