Java 虚拟机将它所管理的内存划分为多个数据区域,分别有程序计数器、虚拟机栈、本地方法栈、堆、方法区、运行期常量池等。另外,这些区域也可以从线程是否共享的角度来进行分析。
1. 程序计数器(Promgram Counter Register)
字节码解释器工作时,通过程序计数器来获取下一条要执行的字节码指令、进行异常处理、线程恢复等。
内容:
- 字节码指令的地址,当线程正在执行的是一个 Java 方法时,计数器中记录正在执行的虚拟机字节码指令的地址
- 空(Undefined)
特点:
- 线程私有,生命周期与线程相同。
- 每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响。
- 唯一一个没有规定任何 OutOfMemoryError 的内存区域
异常: 无
2. Java 虚拟机栈(Java Virtual Machine Stack)
描述 Java 方法执行的线程内存模型:每个方法被执行时,Java 虚拟机都会同步创建一个栈桢(Stack Frame)用户存储局部变量表、操作数栈、动态连接、方法出口等信息。
内容:
- 8 种基本数据类型:boolean、byte、char、short、int、float、long、double
- 对象引用(reference 类型),指向对象起始地址的引用指针、指向一个代表对象的句柄或其他与此对象相关的位置等
- returnAddress 类型,指向一条字节码指令的地址
特点:
- 线程私有,生命周期与线程相同
- 一个方法被调用到执行完的过程,对应着一个栈桢在虚拟机栈中从入栈到出栈的过程。
异常:
- 栈深度溢出:StackOverflowError 异常,线程请求的栈深度大于虚拟机所允许的深度
- 栈扩展失败:OutOfMemoryError 异常,如果 Java 虚拟机栈容量可以动态扩展,则当栈扩展时无法申请到足够内存时会出现该异常
局部变量槽(Slot): 局部变量表中的存储空间以局部变量槽来表示,1 个变量槽实际占用的内存空间大小由具体虚拟机决定。
- long、double 类型的数据占用两个变量槽,其余数据类型只占用一个。
- 局部变量表所需的内存空间在编译期间完成分配。
3. 本地方法栈(Native Method Stacks)
与虚拟机栈的作用很相似,区别在于
- 虚拟机栈:为虚拟机执行 Java 方法(也就是字节码)服务
- 本地方法栈:为虚拟机使用到的本地方法服务
内容:
特点: 虚拟机可以根据需要自由实现本地方法栈,甚至可以将本地方法栈和虚拟机栈合二为一(如:Hot-Spot 虚拟机 )。
异常:(同 Java 虚拟机栈)
- 栈深度溢出
- 栈扩展失败
4. Java 堆(Java Heap)
虚拟机管理的内存最大的一块区域,在虚拟机启动时创建,该区域的唯一目的就是存放对象实例。
内容: 对象实例 特点: 虚拟机管理的内存最大的一块区域 异常:
5. 方法区(Method Area)
用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
内容: 已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
特点: 也被描述为堆的一个逻辑部分,亦称“非堆”(Non-Heap)为了与 Java 堆区分开。
异常: OutOfMemoryError 异常,方法区无法满足新的内存分配需求
该区域的内存回收,主要是针对常量池的回收和对类型的卸载,不过该区域的回收效果比较难令人满意。
6. 运行时常量池(Runtime Constant Pool)
是方法区的一部分,用于存放类在编译期生成的各种字面量与符号(类加载后放入常量池),一般也会把由符号引用翻译出来的直接引用也存储在运行时常量池。
内容: 类在编译期生成的各种字面量与符号(类加载后放入常量池)。
特点:
- 与 Class 文件常量池的一个特征是具备动态性,运行期间也可以将新的常量放入池中,如 String 类的 intern() 。
- 运行时常量池是方法区的一部分,所以也受到方法区内存的限制
异常: OutOfMemoryError 异常
Class 文件常量池
7. 直接内存(Direct Memory)
在 JDK1.4 中新加入的 NIO,可以通过 native 函数直接分配堆外内存,因为避免了在 Java 堆和 Native 堆中来回复制数据,所以在一定场景下可以提高性能。
内容: Java 堆中 DirectByteBuffer 对象保存了对该内存的引用。
特点: 不受 Java 堆大小的限制,但是受本机总内存大小以及物理器寻址空间的限制。
异常: OutOfMemoryError 异常,动态扩展时出现。
Direct Memory 不是虚拟机规范中的内存区域,但是这部分内存也被频繁使用,且也可能导致 OutOfMemoryError 异常。