主要分为 3 块:
- 线程私有区域(程序计数器、虚拟机栈、本地方法栈)
- 线程共享区域(堆、方法区)
- 直接内存(不是 JVM 运行时数据区域的一部分。如 JDK 中的 nio 使用本地函数库分配堆外内存,使用缓冲区进行这块内存的读写)
3 块内存区域的生命周期:
- 线程私有区域,随着用户线程的启动而创建,线程的结束而销毁。
- 线程共享区域,随着虚拟机的启动而创建,虚拟机的停止而销毁。
- 直接内存,通过本地函数库 Unsafe 分配与释放内存。
线程私有区域
1、程序计数器(Program Counter Register)
- 一块较小的内存空间, 是当前线程所执行的字节码的行号指示器
- 每条线程都要有一个独立的程序计数器
- 执行 Java 方法时,程序计数器记录的是字节码指令的地址;执行本地方法时,为空
- 唯一一个没有内存溢出区域
2、虚拟机栈(VM Stack)
- 描述 java 方法执行的内存模型
- 每个方法在执行的同时都会创建一个栈帧(Stack Frame) 用于存储局部变量表、操作数栈、动态链接、方法出口等信息
- 每一个方法从调用直至执行完成的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程
- 栈帧是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁。方法正常完成、抛出异常未捕获都算作方法结束。
3、本地方法栈(Native Method Stack)
- 虚拟机栈为执行 Java 方法服务;本地方法栈为 Native 方法服务
- 本地方法栈深度溢出或者栈扩展失败时,也会分别抛出 StackOverflowError 和 OutOfMemoryError异常
线程共享区域