文章目录
- 1. 程序计数器(Program Counter Register)
- 2. Java虚拟机栈(Java Virtual Machine Stacks)
- 3. 本地方法栈(Native Method Stacks)
- 4. Java堆(Java Heap)
- 5. 方法区(Method Area)
- 运行时常量池(Runtime Constant Pool)
- 直接内存(Direct Memory)
JVM内存模型主要指的是Java虚拟机在运行时管理内存的方式,以及它如何保证线程之间规范而安全地共享数据。JVM内存模型可分为几个关键区域,各自负责不同的功能:

1. 程序计数器(Program Counter Register)
- 作用:程序计数器是一块较小的内存空间,用于记录当前线程所执行的字节码指令的地址,帮助CPU知道下一条要执行的指令。如果线程正在执行的是Java方法,计数器记录的是字节码指令的地址;如果正在执行的是本地(Native)方法,计数器值则为空(Undefined)。
- 线程私有:每个线程都有一个独立的程序计数器,互不影响。
- 无内存溢出:程序计数器是唯一一个在《Java虚拟机规范》中没有规定任何
OutOfMemoryError
情况的区域
2. Java虚拟机栈(Java Virtual Machine Stacks)
- 作用:Java虚拟机栈是线程私有的,用于描述Java方法执行的线程内存模型。每个方法执行时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、 float、long、double)、对象引用(reference类型)
- 这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,在方法运行期间不会改变局部变量表的大小。
- 异常情况:如果线程请求的栈深度大于虚拟机允许的最大深度,将抛出
StackOverflowError
异常;如果栈扩展失败,将抛出OutOfMemoryError
异常。
3. 本地方法栈(Native Method Stacks)
- 作用:线程私有,与虚拟机栈类似,但为虚拟机使用的本地(Native)方法服务。
- 异常情况:与虚拟机栈类似,本地方法栈也会在栈深度溢出或栈扩展失败时分别抛出
StackOverflowError
和OutOfMemoryError
异常。
4. Java堆(Java Heap)
- 作用:Java堆是所有线程共享的一块内存区域,用于存放对象实例。几乎所有的对象实例都在这里分配内存。
- 垃圾回收:Java堆是垃圾收集器管理的主要区域,因此也被称为“GC堆”。
- 异常情况:如果堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出
OutOfMemoryError
异常。 - 从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。在多线程环境中,堆内存是线程共享的,因此对象分配时需要同步操作,这会导致性能下降。TLAB通过为每个线程分配独立的内存空间,避免了多线程之间的内存分配竞争,从而提高了内存分配效率。
5. 方法区(Method Area)
- 作用:逻辑概念,方法区是线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量等数据。
- 异常情况:当方法区无法满足新的内存分配需求时,将抛出
OutOfMemoryError
异常。 - JDK 8的变化:JDK 8及之后的版本将方法区存放在元空间(Metaspace)中,元空间位于操作系统维护的直接内存中。
运行时常量池(Runtime Constant Pool)
- 是方法区的一部分,class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),常量池表中存放了编译期生成的各种字面量和符号引用,具备动态性。
- 当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
直接内存(Direct Memory)
实际上是本机物理内存
- 作用:直接内存不是虚拟机运行时数据区的一部分,但会被频繁使用。它用于NIO等操作,通过
Unsafe
类直接分配内存。 - 异常情况:可能导致
OutOfMemoryError
异常。