跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

JVM 运行时数据区域详解

JVM 运行时数据区域(Runtime Data Area)是 Java 虚拟机在执行 Java 程序过程中所管理的内存区域。需要注意的是,它与 Java 内存模型(Java Memory Model, JMM)是完全不同的概念。JVM 运行时数据区域主要由以下五部分组成: !JVM 运行时数据区域结构 程序计数器(线程私有) 程序计数器(Program Counter Register)是一块较…

极客工坊发布于 2026/3/30更新于 2026/10/2027K 浏览
JVM 运行时数据区域详解

JVM 运行时数据区域(Runtime Data Area)是 Java 虚拟机在执行 Java 程序过程中所管理的内存区域。需要注意的是,它与 Java 内存模型(Java Memory Model, JMM)是完全不同的概念。JVM 运行时数据区域主要由以下五部分组成:

JVM 运行时数据区域结构

1. 程序计数器(线程私有)

程序计数器(Program Counter Register)是一块较小的内存空间,可看作当前线程所执行字节码的行号指示器。如果当前线程正在执行 Java 方法,该计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行 Native 方法,则计数器值为 undefined。程序计数器是 JVM 规范中唯一没有规定任何 OutOfMemoryError 情况的区域。

JVM 通过线程轮流切换来获取 CPU 执行时间。为保证线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器,且各线程间互不干扰,因此它是线程私有的。

以下通过一段简单代码及其字节码指令说明其作用:

public class PcDemo {
    public static int add(int a, int b) {
        return a + b;
    }
}

对应的字节码指令大致如下:

0: iload_0  // 从局部变量表加载变量 a 到操作数栈
1: iload_1  // 从局部变量表加载变量 b 到操作数栈
2: iadd     // 两数相加
3: ireturn  // 返回结果

执行过程:

  1. 初始状态:方法开始执行时,PC 计数器设为 0,指向第一条指令 0: iload_0。
  2. 执行第一条指令:执行 iload_0,将局部变量表索引为 0 的整数(参数 a)压入操作数栈。PC 更新为 1。
  3. 执行第二条指令:执行 iload_1,将索引为 1 的整数(参数 b)压入操作数栈。PC 更新为 2。
  4. 执行第三条指令:执行 iadd,弹出栈顶两个整数相加,结果压回栈顶。PC 更新为 3。
  5. 执行最后一条指令:执行 ireturn,弹出栈顶结果并返回。方法执行完毕。

若发生线程切换,各线程的 PC 值独立保存:

线程 A: PC = 2  // 下一条执行 iadd
线程 B: PC = 4  // 下一条执行 ireturn

2. Java 虚拟机栈(线程私有)

Java 虚拟机栈(JVM Stack)是线程私有的运行时数据区,生命周期与线程相同。它用于描述 Java 方法执行的内存模型:方法调用时,JVM 会创建一个**栈帧(Stack Frame)**并压入虚拟机栈;方法执行结束时,对应栈帧弹出。通常所说的'栈内存'即指此区域。

Java 虚拟机栈结构

栈帧主要包含以下部分:

  • 局部变量表(Local Variable Table):存储方法参数和内部定义的局部变量(基本类型和对象引用)。对象引用保存的是堆中对象的地址。其大小在编译期确定,执行期间不变,以 slot(槽位)形式顺序存放。
  • 操作数栈:JVM 执行字节码指令时临时存放运算数据和结果的栈结构。指令通过入栈(push)和出栈(pop)完成计算,可视为 JVM 的'临时工作台'。
  • 动态链接:在方法执行期间,将常量池中的符号引用解析为实际方法或字段引用的过程。
  • 方法返回地址:当前方法执行结束后,程序返回到调用者方法继续执行的位置(即下一条待执行的字节码地址)。

3. 本地方法栈(线程私有)

本地方法栈(Native Method Stack)与 Java 虚拟机栈作用类似,区别在于:Java 虚拟机栈为 JVM 执行 Java 方法服务,而本地方法栈为 JVM 调用的 Native 方法服务。其异常类型与虚拟机栈相同,此处不再赘述。

4. 堆(线程共享)

堆(Heap)是 JVM 中用于存放对象实例和数组的运行时内存区域,所有线程共享。在 Java 中创建对象时,本质上就是在堆中申请内存。

User user = new User();
// 栈中保存引用 (reference),指向堆中的 User 对象实例
// 真正的对象数据存储在堆中,因此常说 Java 对象'在堆上分配'

堆为何必须共享? 假设堆不共享,每个线程拥有独立的对象副本,将导致数据无法同步。JVM 的设计原则明确:对象数据在堆中共享,执行上下文在栈中隔离。

常见的 JVM 堆内存参数:-Xms(初始堆大小)和 -Xmx(最大堆大小)。

堆也是垃圾收集器(GC)管理的主要区域,常被称为 GC 堆。基于分代收集算法,堆可细分为:

  • 新生代:包含 Eden 区、From Survivor 区、To Survivor 区。
  • 老年代:存放生命周期较长的对象。

细分的目的是为了更高效地分配与回收内存。

堆内存常见的 OutOfMemoryError 类型:

  • java.lang.OutOfMemoryError: GC Overhead Limit Exceeded:JVM 花费过多时间进行垃圾回收,但回收的内存极少。
  • java.lang.OutOfMemoryError: Java heap space:创建新对象时,堆内存不足以分配空间。该错误与配置的 JVM 堆大小有关,而非物理内存不足。

5. 方法区(线程共享)

方法区(Method Area)是 JVM 规范中的逻辑区域,在不同 JDK 版本中有不同实现。JDK 7 及之前称为永久代(PermGen),JDK 8 起永久代被移除,由**元空间(Metaspace)**替代。

注意:方法区是规范概念,元空间是其具体实现方式之一,二者不能直接划等号。

方法区主要存储以下内容:

  1. 类的结构信息(元数据):JVM 加载类时,会将类名、父类、实现的接口、字段信息、方法信息及访问修饰符等解析后存入方法区。
  2. 运行时常量池:每个 class 文件包含常量池,存放字符串常量、类名、方法名、字段名及符号引用等。类加载后,常量池内容进入运行时常量池。例如 String s = "hello"; 中的 "hello" 会进入常量池(注:现代 JVM 中字符串对象实例在堆中,但常量池引用位于方法区/元空间)。
  3. 静态变量(static 变量):属于类级别的变量,不随对象实例分配在堆中,而是存放在方法区。
  4. JIT 编译后的代码:即时编译器(JIT)会将热点方法编译为本地机器码以提升执行效率,编译后的机器码也存储在方法区相关区域。

目录

  1. 1. 程序计数器(线程私有)
  2. 2. Java 虚拟机栈(线程私有)
  3. 3. 本地方法栈(线程私有)
  4. 4. 堆(线程共享)
  5. 5. 方法区(线程共享)

更多推荐文章

查看全部
  • 从零构建并训练 BERT 架构大模型实战指南
  • OpenClaw 实战:持久记忆与 RAG 知识库构建
  • .NET 集成 GoView 低代码可视化大屏方案详解
  • 基于 Python Flask 的电影票房数据采集分析与可视化系统
  • Stable Diffusion WebUI 核心文件夹解析与模型推荐
  • OpenCode 开源 AI 编程代理技术与行业分析
  • FPGA 时序逻辑电路优化实战技巧
  • OpenClaw 部署实战:接入 Minimax/DeepSeek 及飞书机器人
  • 基于 LangChain 实现数据库问答机器人
  • 算法实战:预处理、滑窗、前缀和哈希及图论并查集应用
  • 自主机器人开源教材入门指南
  • 基于 Higress 将 REST API 转换为 MCP Server 工具
  • Python Collections 模块核心数据结构与工具详解
  • DooTask 轻量化与 AI 在开发团队协同中的应用实践
  • VS Code 主流 AI 编程插件功能对比与选型
  • AI 大模型时代下易受影响的 20 种职业分析
  • llama.cpp 启动效率优化指南:从加载延迟到毫秒级响应
  • Go Map 底层原理深度解析
  • 相干伊辛机在医疗领域及医疗AI领域的应用前景分析
  • vLLM + Open-WebUI 部署通义千问 2.5-7B 完整教程

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online