一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

JVM 内存布局和对象访问机制

时间:2026-07-11 09:22:56 编辑:袖梨 来源:一聚教程网

JVM内存布局分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、元空间、运行时常量池)区域;对象在堆中由对象头、实例数据和对齐填充组成;创建经历类检查、内存分配、零值初始化、对象头设置、<init>执行五步;访问方式有句柄和直接指针两种,HotSpot默认用直接指针。

JVM 内存布局和对象访问机制是理解 Java 程序运行本质的关键。简单说,内存布局决定了对象“住哪儿”,而访问机制决定了程序“怎么找到它”。两者紧密配合,共同支撑起 Java 的自动内存管理。

Java 运行时内存区域划分

JVM 将内存划分为线程私有和线程共享两大类区域:

  • 线程私有区域:每个线程独享,包括程序计数器(记录当前执行字节码位置)、Java 虚拟机栈(存放方法调用的栈帧,含局部变量表、操作数栈等)、本地方法栈(为 Native 方法服务);
  • 线程共享区域:所有线程共用,主要包括堆(几乎所有对象实例和数组在此分配)、方法区(JDK 8+ 为元空间,存类信息、常量、静态变量等)、运行时常量池(每个类一份,存字面量与符号引用);
  • 直接内存不属于 JVM 运行时数据区域,但被 NIO 等组件频繁使用,由操作系统直接管理,不受堆大小限制。

对象在堆中的内存布局

一个 Java 对象在堆中实际占据三部分空间:

  • 对象头(Header):包含 Mark Word(存储哈希码、GC 分代年龄、锁状态标志等)和类型指针(指向类元数据,用于确定对象所属类型);
  • 实例数据(Instance Data):真正存储字段内容,按字段宽度排序(long/double → int/float → short/char → byte/boolean → 引用),父类字段排在子类之前;
  • 对齐填充(Padding):非必需,仅用于保证对象起始地址为 8 字节倍数(HotSpot 默认要求),提升 CPU 缓存访问效率。

对象创建的五步流程

执行 new 指令时,JVM 完成以下动作:

  • 检查类是否已加载、解析、初始化,未完成则触发类加载;
  • 根据对象大小,在堆中分配内存:规整堆用“指针碰撞”,不规整堆用“空闲列表”;
  • 将分配到的内存空间初始化为零值(不执行 init 方法,但保证字段可安全读取);
  • 设置对象头,包括类型指针和初始 Mark Word;
  • 执行 <init> 方法,按源码逻辑初始化字段并执行构造函数体。

对象的两种访问定位方式

栈帧中的引用(reference)如何定位到堆中真实对象?主流实现有两种:

  • 句柄访问:堆中划分出句柄池,引用存储的是句柄地址;句柄中包含对象实例数据地址和类型元数据地址。优点是 GC 移动对象时只需改句柄中的实例地址,引用本身不变;
  • 直接指针访问:引用直接存储对象在堆中的起始地址。HotSpot 默认采用此方式,访问更快(少一次指针寻址),但 GC 需同步更新所有引用值。

热门栏目