讲师中心 微信公众号
AI工具推荐 视频效率加速

详解集合在JVM堆内存中的布局_理解对象引用的存储链条

大静君_6998

大静君_6998

发布时间:2026-02-23 18:34:03

|

142人浏览过

|

来源于php中文网

原创

Java对象在堆中分为对象头、实例数据、对齐填充三部分;对象头含Mark Word和Class Pointer;实例数据按字段宽度分组排列;引用变量存于栈或堆,指向堆中对象地址。

详解集合在jvm堆内存中的布局_理解对象引用的存储链条

对象实例在堆里的内存结构长什么样

Java 对象在堆中不是“一块平铺的内存”,而是分三块:对象头、实例数据、对齐填充。对象头里又含 Mark Word(锁状态、GC 分代年龄、哈希码)和 Class Pointer(指向 Klass 元数据)。实例数据才是你声明的 int x、String name 真正存的地方,按字段宽度和继承顺序排列,JVM 可能重排序(比如把两个 byte 挤一起),但不会跨父类边界乱动。

常见错误是以为 new Object() 就占 8 字节——实际在 64 位 JVM(开启指针压缩)下,它至少占 16 字节:12 字节对象头 + 4 字节对齐填充。你可以用 Unsafe.objectFieldOffset() 或 JOL(Java Object Layout)工具验证,别靠猜。

  • 启用指针压缩(默认开启)时,Class Pointer 占 4 字节;关闭后变成 8 字节,对象头整体变大
  • 数组对象多一个 4 字节的 length 字段,放在对象头之后、实例数据之前
  • 子类字段不一定紧跟父类字段——JVM 优先按宽度分组(long/double → int → short/char → byte/boolean),再考虑继承顺序

引用变量到底存在哪?栈上还是堆上

Object obj = new Object(); 这行里,obj 是局部变量,存于当前线程的虚拟机栈帧的局部变量表中;它本身只是个 4 字节(压缩)或 8 字节(未压缩)的引用值,内容是堆中那个对象的起始地址。这个引用不是对象,也不是指针别名,就是个“地址快照”——如果 GC 移动了对象,这个引用值会被 JVM 的写屏障机制悄悄更新。

容易踩的坑:以为 obj 在堆里,或者认为它和 C 的指针一样可做算术运算。它不能解引用、不能加减、不能转成 long 拿来当地址用(除非用 Unsafe,但那是另一套规则)。

  • 成员变量(非 static)的引用字段,和它所属的对象一起存在堆上,属于实例数据的一部分
  • static 字段的引用,存在方法区(JDK 8+ 是元空间)的类元数据结构里,不随对象生命周期变化
  • 逃逸分析后,若确定引用不会被外部访问,JVM 可能把对象直接分配到栈上(标量替换),此时“引用”和“对象”都在栈帧里——但这对 Java 代码完全透明

从引用到对象的完整寻址链条

当你写 obj.toString(),JVM 干的事是:栈上取 obj 的值 → 解释为堆内存地址 → 检查该地址是否在 GC 堆范围内 → 读取该地址处的对象头 → 从中取出 Class Pointer → 查 Klass 结构里的 vtable 或 itable → 找到 toString 方法入口 → 调用。整个链条依赖三个关键环节:引用值有效性、对象头完整性、元数据可达性。

一旦中间某环断掉,就会触发不同错误:引用为 null 抛 NullPointerException;对象已被回收但引用没清(不可能,有 GC 根扫描和写屏障保障);类卸载后调用方法抛 NoClassDefFoundError(注意不是 ClassNotFoundException)。

  • 引用值如果是 0(null),JVM 在方法调用前就检查并抛异常,不走到对象头读取那步
  • 对象头里的 Class Pointer 永远指向有效的 Klass,哪怕类被重新加载——新类会生成新 Klass,老对象仍连着旧的
  • GC 移动对象时,所有指向它的引用(栈上、堆上、常量池里)都会被并发标记-清除阶段统一修正,这个过程对应用线程不可见

为什么 String、Integer 这些看起来像“直接存值”的对象也走这套链条

它们不是特例,只是被设计成不可变且常量化了。String s = "abc" 中,s 还是栈上引用,指向堆里一个真正的 String 实例;而这个实例的 value 字段(JDK 9+ 是 byte[])又是指向另一个堆对象。所谓“字符串常量池”,只是 JVM 维护的一张哈希表,key 是字符内容,value 是堆中对应 String 对象的引用——池里存的仍是引用,不是字符串本体。

有人误以为 Integer.valueOf(127) 返回的是“栈上小整数”,其实它返回的是堆里缓存的 Integer 实例的引用;只有 -128 到 127 范围内才复用,超出就 new 新对象。这和引用存储链条无关,只影响对象数量。

  • String 的 value 字段是引用类型(byte[] 或 char[]),所以字符串内容本身也在堆上,不在字符串对象内部“内联”
  • 自动装箱如 int i = 5; Integer n = i;,n 是栈上引用,指向堆中 Integer 实例;i 才是真正在栈帧里存的 4 字节值
  • final 字段不影响引用存储位置——它只约束后续赋值行为,不改变字段本身的内存布局
事情说清了就结束。真正复杂的是 GC 如何在移动对象的同时维护这张引用网,以及 JIT 如何根据引用链长度做去虚拟化优化——这些底层动作,平时写业务代码几乎感知不到,但一旦出问题(比如 JNI 直接操作了引用地址),排查起来就得一层层剥开对象头、Klass、OopMap 这些东西。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6499

2023.08.02

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

2130

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

163

2025.11.30

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

549

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1698

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6104

2023.10.24

字符串常量的表示方法
字符串常量的表示方法

字符串常量的表示方法:1、使用引号;2、转义字符;3、多行字符串;4、原始字符串;5、字符串连接;6、字符串字面量和对象;7、编码问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1023

2023.12.26

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1758

2023.08.03

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

0

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn