# 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 各个内存区域的作用、垃圾回收机制和并发内存模型,对于面试中涉及性能调优和并发问题的回答有极大帮助。

备案号:粤ICP备2023124211号-1
Copyright © 2023-2024 StarChenTech All Rights Reserved.