Appearance
JVM内存结构 VS Java内存模型 VS Java对象模型
看在前面
三个极易混淆的概念
Java 作为一门面向对象、跨平台的语言,其对象、内存、运行时数据区这类知识点一直比较难。JVM 内存结构、Java 内存模型、Java 对象模型是三个截然不同的概念。但名称相似,很多高级开发也容易弄混:
- JVM 内存结构:Java 虚拟机的运行时数据区(堆、栈、方法区等),与"虚拟机运行"相关。
- Java 内存模型(JMM):Java 并发编程的核心概念,与"并发"相关。
- Java 对象模型(OOP-Klass):Java 对象在虚拟机中的存储模型,与"对象"相关。
JVM 内存结构(Java Memory Structure)
JVM 内存结构是 Java 虚拟机规范中定义的运行时数据区(Runtime Data Areas)。《Java 虚拟机规范(Java SE 8)》规定:程序计数器、Java 虚拟机栈、本地方法栈为线程私有;堆、方法区为线程共享。
程序计数器(Program Counter Register)
- 当前线程所执行字节码的行号指示器。字节码解释器通过改变这个计数器的值来选取下一条要执行的字节码指令。
- 每个线程都有独立的程序计数器,各线程互不影响,独立存储,是唯一不会发生 OutOfMemoryError 的内存区域。
Java 虚拟机栈(Java Virtual Machine Stacks)
- 描述 Java 方法执行的内存模型:每个方法执行都会创建一个栈帧(Stack Frame)。栈帧存储局部变量表、操作数栈、动态链接、方法出口信息。
- 方法从调用到执行完毕,对应栈帧在虚拟机栈中入栈到出栈的过程。
- 可能抛出 StackOverflowError(线程请求的栈深度大于允许的深度)和 OutOfMemoryError(扩展时无法申请到足够内存)。
本地方法栈(Native Method Stack)
- 与虚拟机栈作用类似。区别是虚拟机栈为虚拟机执行 Java 方法服务,本地方法栈为虚拟机使用到的 Native 方法服务。HotSpot 中二者已合一。
Java 堆(Java Heap)
- 虚拟机管理的内存中最大的一块,被所有线程共享,在虚拟机启动时创建。
- 所有的对象实例以及数组都要在堆上分配。随着逃逸分析、标量替换技术的发展,栈上分配、TLAB 这类优化也存在,但堆仍是分配主战场。
- 垃圾收集器管理的主要区域。从内存回收角度可分为新生代(Eden、From Survivor、To Survivor)和老年代。从内存分配角度可划分出多个线程私有的分配缓冲区(TLAB)。
方法区(Method Area)
- 各线程共享的内存区域。存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码这类数据。
- Java 8 中方法区的实现由永久代(PermGen)改为元空间(Metaspace)。元空间使用本地内存,字符串常量池早在 Java 7 就已移到堆中。
- 运行时常量池(Runtime Constant Pool)是方法区的一部分。存放编译期生成的各种字面量和符号引用,具备动态性(String.intern)。
JVM 内存结构的作用
- 规定了 Java 程序运行期间对内存的分配、使用、管理的规则,是 GC、JVM 调优的物理基础。
- 一图胜千言:线程私有的计数器/栈伴随线程创建与销毁。堆与方法区随 JVM 启动创建、随 JVM 退出消亡,堆中对象的回收由 GC 负责。
Java 内存模型(Java Memory Model,JMM)
JMM 的由来
- 并发编程要处理两个关键问题:线程之间如何通信(共享内存 / 消息传递)与线程之间如何同步。
- Java 采用共享内存模型:线程间通信由程序员显式完成,同步也需显式控制。因此需要一套规范来定义线程和内存之间的抽象关系——这就是 JMM(由 JSR-133 定义)。
JMM 的抽象结构:主内存与工作内存
- JMM 规定所有变量都存储在主内存(Main Memory)中,每条线程有自己的工作内存(Working Memory)。
- 工作内存中保存了该线程使用到的变量的主内存副本。线程对变量的所有操作(读取、赋值)都必须在工作内存中完成,不能直接读写主内存中的变量。
- 不同线程之间无法直接访问对方工作内存中的变量。线程间变量值的传递必须通过主内存来完成。线程 A 把工作内存中修改过的共享变量刷新回主内存。线程 B 再从主内存读取更新后的值。
- 这套抽象直接解释了多线程可见性问题的根源。围绕它定义了 volatile、synchronized、final 的语义以及 happens-before 原则,用于保证并发三性:原子性、可见性、有序性。
Java 对象模型(Java Object Model)
- Java 对象在 JVM 中的存储模型叫 OOP-Klass 模型:对象在内存中的布局(oop)与类的元数据(Klass)分离。
- JVM 加载类时会先用 Class 文件创建一个 Klass(C++ 数据结构),保存在方法区,是 Java 类的"身份证"。它包含 vtable(虚方法表)与类信息这类内容。
- new 出来的每个对象实例在堆中对应一个 oop(Ordinary Object Pointer,普通对象指针,C++ 中的 oopDesc)。其中存放对象头(Mark Word、类型指针)与实例数据。
- 由于 JVM 由 C++ 实现,Java 对象在底层并无"C++ 对象模型"那种直接对应。而是通过 oop-Klass 两级模型让 Java 对象既能被 GC 管理,又支持方法分派与类型判断(instanceof、反射都依赖 Klass)。
三者对比总结
- JVM 内存结构:面向"运行时",划分虚拟机运行时数据区,回答"内存区域怎么分、各自放什么"。
- Java 内存模型:面向"并发",定义主内存/工作内存的抽象与同步语义,回答"多线程如何看见彼此的修改"。
- Java 对象模型:面向"对象",描述对象在堆中的存储(oop)与类元数据(Klass)的组织方式。回答"一个 Java 对象在虚拟机里长什么样"。
内容来源:原文 · 2026-10 整理回填。