网站首页 > java教程 正文
Java 内存模型 (Java Memory Model, JMM) 关注的是并发编程。它定义了多线程环境下,线程如何与主内存交互,以及线程之间如何通过共享变量进行通信的规则。它解决的是可见性、有序性、原子性问题,确保多线程程序的正确性。
JVM 内存结构 (JVM Memory Structure / Runtime Data Areas) 关注的是内存管理。它定义了 JVM 在执行 Java 程序时,如何将操作系统分配给它的一大块内存划分成不同的区域,每个区域有特定的用途(如存放对象、方法调用栈、类信息等)。它解决的是内存分配、回收、布局问题。
Java 内存模型
目的
为 Java 程序在多线程环境下的行为提供一个规范和保证。它规定了线程何时以及如何看到其他线程写入共享变量的值,以及指令执行顺序的约束(即使处理器或编译器进行了重排序)。
核心概念
- 主内存 (Main Memory): 所有线程共享的内存区域。存储共享变量的“官方”副本。(注意:这是一个逻辑概念,不一定对应物理上的主内存RAM)
- 工作内存 (Working Memory / Thread Local Memory): 每个线程私有的内存区域。线程对共享变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存。工作内存保存了该线程使用到的共享变量的主内存副本拷贝。
- 内存屏障 (Memory Barriers / Fences): JMM 要求在特定操作(如volatile读写、synchronized块进入/退出、final字段初始化完成等)之间插入内存屏障,以禁止特定类型的处理器重排序,并确保工作内存与主内存的及时同步。
- Happens-Before 原则: JMM 的核心理论,定义了一系列保证操作可见性和有序性的规则。如果操作 A happens-before 操作 B,那么 A 所做的修改(对共享变量)一定对 B 可见,且 A 一定排在 B 之前执行(在可见的层面上)。这个关系是判断线程操作是否安全、是否需要同步的主要依据。
关键问题解决:
- 可见性 (Visibility): 一个线程修改了共享变量,其他线程能立即看到最新值吗?JMM 通过工作内存与主内存的交互规则(如volatile、synchronized、final等关键字触发的同步动作)来保证特定条件下的可见性。
- 有序性 (Ordering): 代码的执行顺序是否一定就是编写的顺序?编译器和处理器为了优化性能会进行指令重排序。JMM 通过happens-before规则限制重排序,保证在单线程内结果正确(as-if-serial语义),并在多线程下提供必要的顺序保证(如volatile禁止重排序规则、synchronized的互斥性)。
- 原子性 (Atomicity): 对基本类型(除long/double外)的读写本身是原子的(在 JVM 实现层面通常保证long/double的原子性)。对于更复杂的操作(如i++),需要synchronized或java.util.concurrent.atomic包下的类来保证原子性。(严格来说,原子性是 CPU 指令集层面保证的,JMM 主要关注的是如何利用这些指令和同步机制来构建正确的并发语义)。
- 体现: volatile, synchronized, final, java.util.concurrent包下的锁和原子类等都直接依赖并实现了 JMM 的规则。
JVM 内存结构 (运行时数据区)
- 目的: 描述 JVM 在运行 Java 程序时,其管理的内存是如何划分区域以及这些区域存储什么内容。
- 核心区域: (基于最常见的 HotSpot JVM)
- 程序计数器 (Program Counter Register): 线程私有。指向当前线程正在执行的字节码指令的地址(如果是 Native 方法则为undefined)。它是控制流的基础。
- Java 虚拟机栈 (Java Virtual Machine Stacks): 线程私有。生命周期与线程相同。存储栈帧 (Stack Frame)。每个方法调用会创建一个栈帧并入栈,方法返回或抛出异常时出栈。
- 栈帧 (Stack Frame): 包含:
- 局部变量表 (Local Variable Array): 存储方法参数和方法内部定义的局部变量(基本类型值、对象引用)。
- 操作数栈 (Operand Stack): 用于执行字节码指令时存放临时操作数和中间结果(类似 CPU 的寄存器作用)。
- 动态链接 (Dynamic Linking): 指向运行时常量池中该栈帧所属方法的引用,支持方法调用过程中的动态连接。
- 方法返回地址 (Return Address): 方法正常退出或异常退出的地址。
- 本地方法栈 (Native Method Stack): 线程私有。为 JVM 调用 Native (非 Java) 方法服务。具体实现由 JVM 供应商决定,甚至可能和 Java 虚拟机栈合并。
- Java 堆 (Java Heap): 所有线程共享。JVM 管理的最大一块内存。存放对象实例和数组。是垃圾收集器 (Garbage Collector, GC) 管理的主要区域。通常被划分为不同的代(Young/Old Generation)以优化 GC。
- 方法区 (Method Area): 所有线程共享。存储已被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。逻辑上是堆的一部分,但规范允许独立实现。
- 运行时常量池 (Runtime Constant Pool): 方法区的一部分。存储类文件中的常量池表内容(字面量、符号引用),在类加载后进入运行时常量池。也支持动态添加(如String.intern())。
- 直接内存 (Direct Memory): 这不是 JVM 规范定义的内存区域,但非常重要。Java 程序可以通过java.nio包下的ByteBuffer.allocateDirect()方法申请,这块内存由操作系统管理,但 Java 代码可以通过DirectByteBuffer对象间接操作。它避免了在 Java 堆和 Native 堆之间复制数据,提高了 I/O 效率。其大小不受-Xmx等参数限制,但受操作系统内存限制。它的回收依赖于DirectByteBuffer对象本身被 GC 回收时触发的Cleaner机制(或显式调用System.gc(),但不可靠),可能导致OutOfMemoryError: Direct buffer memory。
猜你喜欢
- 2025-07-19 Java AtomicInteger操作详解(java attachment)
- 2025-07-19 无锁同步-JAVA之Volatile、Atomic和CAS
- 2025-07-19 Java 作用域详解:从变量可见性到代码封装
- 2025-07-19 CompletableFuture源码分析(fragment源码分析)
- 2025-07-19 Java并发编程从入门到进阶 多场景实战
- 2025-07-19 一文搞懂 CAS 操作与 ABA 问题:高并发编程的关键知识点
- 2025-07-19 Java面试必备八股文(java面试必备八股文河北人社)
- 2025-07-19 Java面试都在问的CAS,你还没掌握吗?
- 2025-07-19 java VarHandle介绍(java variant)
- 2025-07-19 【多线程】Java多线程与并发编程全解析
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)