# JVM 内存模型
# 1. JVM 内存模型概述
JVM 内存模型 (Java Memory Model, JMM) 定义了 Java 虚拟机在执行 Java 程序时如何管理内存,主要包括程序运行时的内存区域划分、内存的管理与分配、垃圾回收等。
JVM 的内存区域可分为以下几部分:
- 堆 (Heap):用于存储所有对象实例,所有线程共享的内存区域。
- 方法区 (Method Area):存储类信息、常量、静态变量等,也属于共享内存。
- 虚拟机栈 (Java Stack):每个线程独有,存储方法的局部变量表、操作数栈、动态链接等。
- 本地方法栈 (Native Method Stack):为本地方法服务的栈,存储本地方法调用的局部变量。
- 程序计数器 (Program Counter, PC):记录当前线程所执行的字节码行号。
- 直接内存 (Direct Memory):不属于 JVM 内存管理,但被 NIO 使用。
# 2. JVM 内存区域详解
# 2.1 堆 (Heap)
- 用途:所有对象实例和数组都在堆中分配。堆是线程共享的区域,分为年轻代 (Young Generation) 和老年代 (Old Generation)。
- GC 相关:堆是垃圾回收器(GC)管理的主要区域,特别是年轻代中的 Eden 区 和 Survivor 区 参与频繁的垃圾回收。
# 2.2 方法区 (Method Area)
- 用途:存储已加载的类信息、常量池、静态变量和方法代码。方法区也是共享的,但在 HotSpot 中与堆一样会发生垃圾回收。
- 特点:在 JDK 8 之前,方法区的实现称为 永久代 (PermGen);JDK 8 之后,永久代被 元空间 (Metaspace) 取代,元空间使用的是直接内存。
# 2.3 虚拟机栈 (Java Stack)
- 用途:每个线程有独立的虚拟机栈,存储每个方法的局部变量表。局部变量表中的数据类型包括基本数据类型和对象的引用。
- 栈帧 (Stack Frame):虚拟机栈中的每个方法执行时对应一个栈帧,用来存储方法的局部变量、操作数栈和动态链接。
# 2.4 本地方法栈 (Native Method Stack)
- 用途:与虚拟机栈类似,但本地方法栈为本地方法服务。主要用于调用本地的 C/C++ 代码。
# 2.5 程序计数器 (PC Register)
- 用途:记录当前线程所执行字节码的行号。如果线程正在执行本地方法,程序计数器为空。
# 3. 垃圾回收 (Garbage Collection, GC) 与内存管理
# 3.1 GC 的基本概念
垃圾回收 是 JVM 中用于自动管理内存的机制,通过检测对象的引用,自动回收不再使用的对象。GC 主要在堆中进行,特别是在年轻代 (Young Generation) 和老年代 (Old Generation) 之间。
# 3.2 垃圾回收算法
- 引用计数算法:通过维护对象的引用计数来判断是否可以回收,但无法处理循环引用问题。
- 标记-清除算法 (Mark-Sweep):先标记所有可达对象,再清除不可达对象。
- 标记-整理算法 (Mark-Compact):标记可达对象后,将存活对象移动到堆的一端,避免内存碎片。
- 复制算法 (Copying):将所有存活对象从一个区域复制到另一个区域,适用于年轻代。
# 3.3 分代收集理论
JVM 将堆分为年轻代和老年代,基于 对象的存活周期 进行分代垃圾回收:
- 年轻代:对象生命周期短,常采用复制算法。包括 Eden 区、From Survivor 区和 To Survivor 区。
- 老年代:生命周期较长的对象,通常采用标记-整理或标记-清除算法。
# 3.4 常见垃圾回收器
- Serial GC:单线程收集器,适用于单核处理器。
- Parallel GC:多线程收集器,适用于多核处理器。
- CMS GC (Concurrent Mark-Sweep GC):低停顿的收集器,适用于注重响应时间的应用。
- G1 GC:自适应分代收集器,适用于大堆内存应用。
# 常见面试问题:
- 垃圾回收的原理是什么?
- JVM 中常见的垃圾回收算法有哪些?
- 什么是 G1 GC?它与 CMS GC 的区别是什么?
# 4. JVM 内存模型与并发
# 4.1 JMM (Java Memory Model) 与线程间通信
Java 内存模型 (JMM) 规定了多线程间如何共享变量,以及在不同线程之间如何保证内存可见性和有序性。JMM 的主要目标是解决线程之间的内存可见性问题。
# 4.2 内存可见性问题
在多线程环境下,一个线程对共享变量的修改,可能不会立即被另一个线程看到,造成可见性问题。为解决该问题,Java 提供了 volatile 关键字、锁和原子操作。
# 4.3 happens-before 原则
JMM 定义了 happens-before 规则来确保操作的有序性。具体规则包括:
- 程序顺序原则:单线程内操作按程序顺序执行。
- 锁定规则:一个锁的解锁操作
unlock
必须发生在随后对该锁的加锁lock
操作之前。 - volatile 变量规则:对
volatile
变量的写操作先行发生于后续对该变量的读操作。
# 5. 结论
JVM 内存模型是理解 Java 程序性能、内存管理和多线程并发行为的基础。掌握 JVM 各个内存区域的作用、垃圾回收机制和并发内存模型,对于面试中涉及性能调优和并发问题的回答有极大帮助。
← Java垃圾回收调优 JVM参数调优 →