JVM内存模型(JMM)
1. 什么是JVM内存模型
JVM内存模型(Java Memory Model,简称JMM)定义了Java程序中多线程访问内存时的行为,确保在不同的硬件和操作系统上Java程序能表现出一致的行为。JMM规定了可见性、原子性、有序性等内存操作的规则,主要用于多线程共享数据的管理。
2. JVM内存区域
JVM内存模型将内存划分为多个区域,每个区域承担不同的角色:
-
程序计数器(PC Register)
- 每个线程有一个独立的程序计数器,存储当前线程正在执行的字节码的地址。
- 线程私有,不参与垃圾回收。
-
JVM栈(Stack)
- 每个线程有一个独立的栈,栈中存储方法的局部变量、操作数栈和帧数据。
- 局部变量表存放基本类型和对象引用,不直接存储对象。
- 栈是线程私有的。
-
本地方法栈(Native Stack)
- 类似于JVM栈,但用于支持Native方法的调用。
-
堆(Heap)
- 存储对象实例和数组,是垃圾回收的主要区域。
- 堆是所有线程共享的,且内存的分配和回收由GC负责。
-
方法区(Method Area)/元空间(Metaspace)
- 存储类信息、常量、静态变量和即时编译器编译后的代码。
- 在JDK 8及以后,方法区已被替换为元空间(Metaspace),元空间存储在本地内存中。
-
直接内存(Direct Memory)
- 不属于JVM内存的一部分,由操作系统直接管理,用于提高I/O性能。
3. JMM的核心概念
-
可见性:
- 在多线程环境中,一个线程对共享变量的修改,其他线程是否能立即看到。
- 通过
volatile
关键字、synchronized
关键字来保证可见性。
-
原子性:
- 操作是不可分割的,要么全部执行,要么全部不执行。
- 基本类型的赋值操作和
final
变量赋值具有原子性,复杂操作需要同步机制。
-
有序性:
- 程序的执行顺序应该是符合代码书写顺序的。
- Java中通过
happens-before
规则来保证有序性。
4. 线程与内存的交互
JMM定义了线程间如何共享数据的规则。具体表现为:
- 同步:通过
synchronized
、Lock
等机制确保线程安全。
- 内存屏障:JMM通过内存屏障来强制指令顺序,防止指令重排。
5. 垃圾回收机制与JVM内存模型
- **垃圾回收(GC)**主要回收堆内存区域,使用不同的算法(如标记-清除、标记-整理、复制算法等)进行对象清理。
- 分代收集:JVM内存模型采用分代垃圾回收机制,将堆划分为年轻代和老年代,提升GC效率。
6. JMM相关的关键字
- volatile:确保变量在不同线程间的可见性,不保证原子性。
- synchronized:确保在多线程访问共享资源时的可见性、原子性和有序性。
- final:确保对象在构造完成后,线程可以安全地访问其状态。
7. 总结
JVM内存模型是Java多线程编程中非常重要的一部分,通过理解JMM的可见性、原子性和有序性等原则,可以帮助开发者编写出线程安全的Java程序。