0%

Java 内存区域

一、程序计数器

  • def 一块较小的内存空间,可看作当前线程所执行字节码的行号指示器

  • 作用 用来存储指向下一条指令的地址,供执行引擎读取

    • 直观的说法是,程序计数器用于记录当前代码执行的位置
    • 类比物理寄存器的 PC,JVM 中的 PC 寄存器是它的抽象模拟

1. 特点

  • 线程私有,生命周期和线程一致

    • 每个线程都有其程序计数器,互不影响、独立存储
  • 程序控制流的指示器:分支、循环、跳转、异常处理、线程恢复等功能都依赖其完成

  • 根据线程正在执行方法的不同,其记录的值不同

    • 若为 Java 方法,记录 JVM 字节码指令的地址
    • 若为 Native 方法,置空(undefined)
  • 唯一没有规定任何 OutOfMemoryError 的区域

2. 相关问题

 点击折叠

Q1:为什么程序计数器被设定为线程私有的

A:因为 Java 中的多线程实际上是通过各线程之间轮流切换、分配 CPU 处理时间来实现的,任一确定的时刻,CPU 只执行一条线程中的指令;为了在线程切换后能够恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,其内存区域是线程私有的。

Q2:为什么使用 PC 寄存器记录当前线程的执行地址

A:字节码解释器(interpreter)需要通过改变程序计数器的值,来明确下一条应该执行的字节码指令

二、虚拟机栈

  • def 描述 Java 方法执行时的线程内存模型:每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的 Java 方法调用

  • 作用 主管 Java 程序的运行

1. 特点

  • 线程私有,生命周期和线程一致

  • JVM 直接对虚拟机栈进行的操作只有两个:方法执行入栈,执行结束出栈

  • 可由线程固定或动态扩展内存大小,不存在垃圾回收问题

    • 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出 StackOverflowError 异常
    • 对动态扩展栈,若没有足够的内存,JVM 将抛出 OutOfMemoryError 异常

2. 栈帧的构成

  • 局部变量表(Local Variables):存储方法参数和定义在方法体内的局部变量,如基本数据类型、对象引用等

    • 基本存储单元:局部变量槽(slot),32 位以内的类型占用一个 Slot,64 位的类型占用两个连续的 Slot
  • 操作数栈(Operand Stack):在方法执行过程中,根据字节码指令,往操作数栈中写入数据或提取数据,即入栈(push)、出栈(pop)

    • 主要用于保存计算的中间结果,并作为计算过程中变量的临时存储空间
  • 动态链接(Dynamic Linking):每个栈帧内部均包含一个可指向当前方法所在类的运行时常量池,该栈帧所属方法的引用,以实现动态链接

  • 方法返回地址(Return Address):存放调用该方法的程序计数器的值

    • 正常返回出口:返回值传递给上层的方法调用者
    • 异常返回出口:不产生任何返回值
  • 附加信息

3. 相关问题

 点击折叠

Q1:栈帧的创建 / 销毁时机

A:当方法被执行时,JVM 会同步创建一个栈帧;方法从调用到执行结束的过程,对应着栈帧在虚拟机栈从入栈到出栈的过程。

Q2:如何访问局部变量表中一个 64bit 的局部变量值

A:JVM 会为局部变量表中的每一个局部变量槽都分配一个访问索引,因为 64bit 的局部变量值占据两个 slot 空间,故应使用该局部变量的前一个索引访问(不能采用任何方式单独访问其中的某一个 Slot)

三、本地方法栈

  • 作用 主管本地方法(native method)的调用

1. 特点

  • 线程私有,生命周期和线程一致

  • 可由线程固定或动态扩展内存大小

    • 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出 StackOverflowError 异常
    • 对动态扩展栈,若没有足够的内存,JVM 将抛出 OutOfMemoryError 异常
  • optional:不是所有的 JVM 都支持

在 Hotspot JVM 中,本地方法栈和虚拟机栈是合二为一的

2. 本地方法接口,JNI

  • def 一个 Java 调用本地方法的接口

  • 作用 提高程序编译效率,并适用于与外部环境交互

本地方法使用 C 实现

四、堆

  • 作用 存放对象实例,几乎所有对象实例和数据均在此分配内存

  • 注:JDK1.7 后,字符串常量池从方法区移动到了堆中

1. 特点

  • 所有线程共享

  • 是虚拟机所管理的最大一块内存

五、方法区

  • 作用 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器的代码缓存等数据

1. 特点

  • 所有线程共享

2. 方法区的构成

  • 类信息表

  • 运行时常量池



参考资料:

  1. 《深入理解 Java 虚拟机(第 3 版)》,周志明著

  2. JVM 基础 - JVM 内存结构 | Java 全栈知识体系 (pdai.tech)

  3. Java JVM 虚拟机 已完结(IDEA 2021 版本)4K 蓝光画质 全程劝退