从零起步学习JVM|| 第二章:JVM基本组成及JVM内存区域详解

Q1:JVM由哪些部分组成?

A1:

1. 类加载器子系统 (Class Loader Subsystem)

负责加载、链接和初始化类。它将 .class 文件加载到内存中,并生成对应的 java.lang.Class 对象。

  • 功能
    • 加载 (Loading):查找并读取类的二进制数据。
    • 链接 (Linking):验证、准备、解析(将符号引用替换为直接引用)。
    • 初始化 (Initialization) :执行类构造器 <clinit>() 方法,给静态变量赋初值。
  • 分类 (双亲委派模型):
    • 启动类加载器 (Bootstrap ClassLoader) :加载核心类库(rt.jar 等),由 C++ 实现。
    • 平台类加载器 (Platform ClassLoader):Java 9 之前称为扩展类加载器,加载扩展类库。
    • 应用类加载器 (Application ClassLoader):加载用户类路径(Classpath)下的类。

2. 运行时数据区 (Runtime Data Area)

这是 JVM 的内存模型,是 JVM 规范中最核心的部分。它分为线程私有线程共享两大部分:

线程私有(随线程生灭)
  1. 程序计数器 (Program Counter Register)
    • 记录当前线程所执行的字节码的行号指示器。
    • 是唯一一个在 JVM 规范中没有规定任何 OutOfMemoryError 情况的区域。
  2. Java 虚拟机栈 (Java Virtual Machine Stack)
    • 描述 Java 方法执行的内存模型。
    • 每个方法执行时会创建一个栈帧 (Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
    • 可能抛出 StackOverflowError(栈深度过深)或 OutOfMemoryError(栈扩展失败)。
  3. 本地方法栈 (Native Method Stack)
    • 与虚拟机栈作用相似,但服务于 Native 方法(通常由 C/C++ 编写)。
线程共享(随 JVM 生灭)
  1. 堆 (Heap)
    • 最大的一块内存区域
    • 存放对象实例数组
    • 垃圾收集器 (Garbage Collector) 管理的主要区域。
    • 可能抛出 OutOfMemoryError
  2. 方法区 (Method Area) / 元空间 (Metaspace)
    • 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。
    • 注意:在 Java 8 及之后,方法区的实现由"永久代 (PermGen)"改为"元空间 (Metaspace)",直接使用本地内存,不再受 JVM 堆内存限制(但受物理内存限制)。

3. 执行引擎 (Execution Engine)

负责执行字节码,是 JVM 的核心。

  • 解释器 (Interpreter)
    • 逐行读取字节码并立即执行。启动速度快,但运行效率相对较低。
  • 即时编译器 (JIT Compiler, Just-In-Time)
    • 将热点代码(频繁执行的代码)编译成本地机器码,并缓存起来。
    • 下次执行时直接运行机器码,大幅提升运行效率。
    • HotSpot 虚拟机中包含 C1(客户端编译器)和 C2(服务器端编译器)。
  • 垃圾回收器 (Garbage Collector)
    • 虽然 GC 主要作用于堆内存,但在架构上常被视为执行引擎的一部分或独立模块。
    • 负责自动回收不再使用的对象,释放内存。

4. 本地方法接口 (Native Interface)

  • JNI (Java Native Interface)
  • 它的作用是融合不同的编程语言为 Java 所用。
  • 当 Java 代码需要调用非 Java 语言(如 C、C++)编写的方法时,通过 JNI 进行交互。

Q2:JVM内存区域是什么样的?

A2:

下图来自Java内存区域详解(重点) | JavaGuide

一、线程私有区域(随线程创建/销毁)

1. 程序计数器(Program Counter Register)

  • 作用:记录当前线程正在执行的字节码指令地址(行号指示器)。
  • 特点
    • 唯一 不会发生 OutOfMemoryError 的区域。
    • 线程切换时,PC 计数器会保存当前执行位置,恢复时继续执行。
    • 若执行的是 Native 方法,计数器值为空(Undefined)。

2. Java 虚拟机栈(Java Virtual Machine Stack)

  • 作用 :描述 Java 方法执行的内存模型,每个方法调用会创建一个栈帧(Stack Frame)
  • 栈帧包含
    • 局部变量表(Local Variables)
    • 操作数栈(Operand Stack)
    • 动态链接(Dynamic Linking)
    • 方法返回地址(Return Address)
  • 异常
    • StackOverflowError:线程请求栈深度超过虚拟机允许的最大深度(如递归过深)。
    • OutOfMemoryError:栈可动态扩展时,扩展失败。

3. 本地方法栈(Native Method Stack)

  • 作用 :为 Native 方法(C/C++ 编写)服务,与虚拟机栈功能类似。
  • 特点:具体实现由虚拟机自行决定,HotSpot 将其与 Java 虚拟机栈合二为一。

二、线程共享区域(随 JVM 启动/销毁)

4. 堆(Heap)

  • 作用最大的内存区域 ,存放对象实例数组
  • 特点
    • 垃圾收集器(GC)管理的主要区域,几乎所有对象都在堆上分配。
    • 可细分为 新生代(Young Generation)老年代(Old Generation) (HotSpot 实现):
      • 新生代:Eden 区 + Survivor 区(From/To)
      • 老年代:存放长期存活对象
    • 可通过 -Xms(初始堆大小)和 -Xmx(最大堆大小)调整。
  • 异常OutOfMemoryError: Java heap space(堆内存不足)。

5. 方法区(Method Area)

  • 作用 :存储类元数据 ,包括:
    • 类信息(字段、方法、接口等)
    • 运行时常量池(Runtime Constant Pool)
    • 静态变量
    • JIT 编译后的代码缓存
  • 重要演变
    • Java 7 及之前 :HotSpot 使用 永久代(PermGen) 实现方法区,位于 JVM 堆内。
    • Java 8 及之后 :永久代被移除,改用 元空间(Metaspace) ,使用本地内存(Native Memory) ,不再受 -Xmx 限制。
      • 元空间大小默认仅受系统物理内存限制,可通过 -XX:MaxMetaspaceSize 限制。
      • 类元数据的垃圾回收更高效,避免了永久代常见的 OutOfMemoryError: PermGen space 问题。
  • 异常OutOfMemoryError: Metaspace(元空间耗尽)。

💡 运行时常量池 是方法区的一部分,用于存放编译期生成的字面量和符号引用,在类加载后存入。例如 String s = "hello" 中的 "hello" 会进入常量池。

Q3:Java堆空间的基本结构是什么样子的?

A3:

下图来自JVM垃圾回收详解(重点) | JavaGuide

新生代(Young Generation)

  • Eden 区 :新对象优先分配于此(TLAB 优化下线程本地分配)。
  • Survivor 区 (S0/S1):
    • Minor GC 时,Eden + From Survivor 中存活对象复制到 To Survivor
    • 每次 GC 后 S0/S1 角色互换("复制算法"核心)。
    • 对象年龄 +1,达到阈值(-XX:MaxTenuringThreshold,默认15)晋升老年代。
  • 特点:高频 Minor GC(Stop-The-World 时间短),回收"朝生夕死"对象。

老年代(Old/Tenured Generation)

  • 存放:
    • 经多次 Minor GC 仍存活的对象
    • 大对象(-XX:PretenureSizeThreshold 直接分配至此)
    • Survivor 空间不足时的担保晋升对象
  • GC 行为:触发 Major GC / Full GC(耗时长,需避免频繁发生)。

Q4:Java虚拟机栈和栈帧是什么?

A3:

相关推荐
于先生吖1 小时前
前后端分离开发 Java 跑腿系统:用户 + 骑手 + 后台三端实战
java·开发语言
iPadiPhone2 小时前
Java NIO 核心原理解析、性能调优与大厂面试精要
java·后端·面试·nio
2401_891482172 小时前
C++中的原型模式
开发语言·c++·算法
罗罗攀2 小时前
PyTorch学习笔记|张量的线性代数运算
人工智能·pytorch·笔记·学习·线性代数
vx-bot5556662 小时前
企业微信ipad协议的防封号技术体系与策略实践
服务器·企业微信·ipad
史蒂芬_丁2 小时前
C++静态变量管理实例
开发语言·c++
木子欢儿2 小时前
在 Debian 12 上安装多个版本的 php(7.3、7.4、8.1、8.2)
运维·开发语言·debian·php
2301_795741792 小时前
C++中的代理模式变体
开发语言·c++·算法
hnlgzb2 小时前
Gemini:kotlin这几个类型有什么区别?类比java的文件,是怎样的?
java·开发语言·kotlin