jvm内存划分为五大运行时数据区:程序计数器、java虚拟机栈、本地方法栈(线程私有);堆、方法区(线程共享)。对象在堆中布局为对象头、实例数据和对齐填充;hotspot采用直接指针访问方式,引用存于栈中指向堆内对象地址。

Java虚拟机(JVM)的内存区域划分和对象访问方式,是理解Java程序运行机制的核心基础。关键在于区分“线程私有”与“线程共享”区域,并明确对象创建、布局与引用之间的关系。
五大运行时数据区及其职责
JVM将管理的内存划分为五个逻辑区域,按线程可见性分为两类:
- 线程私有区域:每个线程独有一份,互不干扰 • 程序计数器:记录当前线程执行到哪条字节码指令;执行Java方法时存地址,执行Native方法时为空;是唯一不会发生OutOfMemoryError的区域 • Java虚拟机栈:方法调用时创建栈帧,存储局部变量表、操作数栈、动态链接等;栈深度超限抛StackOverflowError,申请空间失败则可能抛OutOfMemoryError(HotSpot默认不支持动态扩展) • 本地方法栈:专为Native方法服务,作用类似虚拟机栈
- 线程共享区域:所有线程共用,需考虑并发安全 • 堆(Heap):几乎所有对象实例和数组都在这里分配;是垃圾回收的主要区域;容易出现OutOfMemoryError;JDK 8起采用分代设计(新生代/老年代),并配合G1、ZGC等收集器优化 • 方法区(Metaspace):JDK 8取消永久代,改用本地内存实现的元空间,存放类信息、常量、静态变量、即时编译器代码等;字符串常量池已移至堆中
对象在堆中的内存布局
一个对象在堆中实际占据三块连续空间:
- 对象头:包含Mark Word(存储哈希码、GC分代年龄、锁状态等)和类型指针(指向方法区中的类元数据)
- 实例数据:字段内容,按宽度从大到小排列(如long/double优先,int次之),以提升内存对齐效率
- 对齐填充:非必需,仅用于保证对象起始地址为8字节整数倍(HotSpot默认要求)
对象的访问定位方式
Java程序通过引用来操作对象,而引用本身存于栈帧的局部变量表中。JVM有两种主流访问方式:
- 句柄访问:堆中划分出一块句柄池,引用存储的是句柄地址;句柄中保存对象实例数据地址和类型数据地址;优势是对象移动时只需修改句柄中的实例地址,引用本身无需更新
- 直接指针访问:引用直接存储对象在堆中的起始地址;HotSpot虚拟机采用此方式,节省一次指针跳转开销,提升访问速度;但对象移动(如GC整理)时需逐个修正所有引用
对象创建与引用的本质关系
对象一定分配在堆中,但引用变量本身一定在栈(或静态字段、其他对象字段)中。例如:
Student stu = new Student();→ stu 是栈中引用变量,值为堆中某个Student对象的地址(或句柄);new Student() 触发类加载、内存分配、初始化等完整流程;该对象后续是否被GC,取决于是否存在可达的引用链。











