Skip to content

JVM 内存模型

一、JVM 内存模型:堆与栈

1. 逻辑划分
  • 线程栈(Thread Stack):线程私有,存储方法调用相关数据。
  • 堆(Heap):线程共享,存储所有对象实例。
2. 堆栈内容
  • 线程栈
  • 存储每个方法调用的局部变量(基本类型和对象引用)。
  • 基本类型(如 intdouble)完全存储在栈中,线程隔离。
  • 对象引用存储在栈中,指向堆中的对象。
  • 每个线程有独立的栈,互不干扰。
  • 存储所有对象实例(包括基本类型包装类如 Integer)。
  • 对象的成员变量(基本类型或引用)随对象存储在堆中。
  • 静态变量随类定义存储在堆中。
3. 线程栈访问堆
  • 机制
  • 线程通过栈中的对象引用访问堆中对象。
  • 多个线程可引用同一对象,访问其成员变量。
  • 示例java public class MyRunnable implements Runnable { public void run() { methodOne(); } public void methodOne() { int localVariable1 = 45; // 栈中基本类型 MySharedObject localVariable2 = MySharedObject.sharedInstance; // 栈中引用,指向堆 methodTwo(); } public void methodTwo() { Integer localVariable1 = new Integer(99); // 栈中引用,新对象在堆 } } public class MySharedObject { public static final MySharedObject sharedInstance = new MySharedObject(); // 静态变量在堆 public Integer object2 = new Integer(22); // 成员变量在堆 public Integer object4 = new Integer(44); public long member1 = 12345; // 基本类型成员变量在堆 }
  • 分析
  • localVariable1int)在栈中,线程隔离。
  • localVariable2 引用堆中共享对象 sharedInstance
  • methodTwo 中的 localVariable1 引用堆中新 Integer 对象。
  • 多个线程运行时,各有栈帧,但共享堆中对象。

二、JMM 与硬件内存结构关系

1. 硬件内存结构
  • 架构
  • CPU:多核,每个核可运行一个线程。
  • 寄存器:最快存储,操作数据。
  • CPU 缓存:介于寄存器和主存,加速访问。
  • 主存(RAM):所有 CPU 共享,容量大但较慢。
  • 数据流
  • CPU 从主存读取数据到缓存/寄存器。
  • 操作后刷新回缓存,再回主存。
2. JMM 与硬件映射
  • 逻辑 vs 物理
  • JMM 的栈和堆在硬件上都映射到主存。
  • 栈帧和局部变量可能缓存到 CPU 寄存器或缓存。
  • 问题
  • 可见性:线程更新共享变量可能未及时刷新到主存,其他线程不可见。
  • 竞态条件:多线程并发更新共享变量,可能导致数据不一致。
3. 可见性问题
  • 场景
  • 线程 A 更新堆中对象变量,缓存未刷新到主存。
  • 线程 B 从主存读取旧值。
  • 解决
  • volatile:确保变量直接读写主存。
  • 示例
  • 线程 A 将共享对象 count 改为 2,未刷新。
  • 线程 B 仍看到旧值 1。
4. 竞态条件
  • 场景
  • 线程 A 和 B 同时对共享变量 count 增 1。
  • 未同步,可能只增 1 次而非 2 次。
  • 解决
  • synchronized:保证单线程访问,刷新变量到主存。
  • 示例
  • count 初始为 0,A 和 B 各增 1。
  • 无同步,可能最终为 1。

三、运行时数据区总结

1. 线程私有
  • 程序计数器:记录指令地址,无 OOM。
  • 虚拟机栈
  • 栈帧存储局部变量(基本类型在栈,引用指向堆)。
  • 操作数栈、动态链接等支持方法执行。
  • 本地方法栈:管理 Native 方法调用。
2. 线程共享
  • 存储对象实例、成员变量、静态变量。
  • 分代(年轻代、老年代)优化 GC。
  • 方法区
  • 存储类信息、常量池、静态变量(JDK 8 后部分移至堆)。
  • 元空间(JDK 8)使用本地内存。
3. 堆栈交互
  • 栈访问堆:通过引用操作堆中对象。
  • 硬件支持:栈和堆数据可能缓存到寄存器或 CPU 缓存,需同步机制确保一致性。

四、参考与思考

  • JMM 的抽象:屏蔽硬件差异,提供一致性模型。
  • 优化volatilesynchronized 解决可见性和竞态问题。
  • 实践:理解堆栈分工有助于调试多线程问题和内存管理。