0

0

详解Java中的对象内存布局_对象头、实例数据与对齐填充

P粉602998670

P粉602998670

发布时间:2026-02-14 12:32:02

|

965人浏览过

|

来源于php中文网

原创

对象头存mark word和class pointer;hashcode()调用后哈希值写入mark word并固化,覆盖偏向锁信息,导致锁撤销且影响内存布局。

详解java中的对象内存布局_对象头、实例数据与对齐填充

对象头里存了啥,为什么 hashCode() 会改变对象内存布局

Java 对象在堆中不是随便放的,对象头是 JVM 管理对象的“身份证”。它通常包含两部分:Mark WordClass Pointer(开启压缩指针时占 4 字节,否则 8 字节)。Mark Word 复用程度极高——锁状态、GC 分代年龄、偏向线程 ID 全挤在这 8 字节里。重点来了:调用过 Object.hashCode() 的对象,JVM 会在 Mark Word 中写入哈希值,这会覆盖原本可能存放的偏向锁信息;一旦写入,这个哈希值就固化了,哪怕对象被移动(GC 搬家),JVM 也会从对象头里读出原值,不再重新计算。

常见错误现象:System.identityHashCode(obj)obj.hashCode() 在重写了 hashCode() 的类上结果不同,但如果你没重写,又发现两次调用 obj.hashCode() 返回值不一致——那说明对象还没被“哈希固化”,且期间发生过 GC 导致对象移动、JVM 重算了地址哈希(仅限未调用过、未锁、未进入老年代的对象)。

  • 不要依赖未重写的 hashCode() 做唯一标识,尤其在缓存 key 或序列化场景
  • 开启 -XX:+UseBiasedLocking(JDK 15+ 默认关闭)时,偏向锁标记和哈希值互斥,首次调用 hashCode() 会直接撤销偏向
  • Mark Word 在 64 位 JVM 上默认 8 字节,但启用 -XX:+UseCompressedOops(默认开)且堆 ≤ 32GB 时,Class Pointer 压缩为 4 字节,对象头共 12 字节(非 16)

实例数据排列顺序真由字段声明顺序决定吗

不一定。JVM 会对字段做**重排序(reordering)**,目标是减少内存空洞、提升 CPU 缓存行利用率。规则是:按宽度从大到小排——long / doubleint / floatchar / shortbyte / boolean → 引用类型(压缩后 4 字节)。同一宽度字段才按源码顺序排。

使用场景:写高性能缓存或需要精确控制对象大小(如 Netty 的 ByteBuf 内部对象)、排查 false sharing(伪共享)问题时,必须看真实布局,不能信源码顺序。

立即学习Java免费学习笔记(深入)”;

What-the-Diff
What-the-Diff

检查请求差异,自动生成更改描述

下载
  • Unsafe.objectFieldOffset() 或 JOL(Java Object Layout)工具验证实际偏移,例如 new org.openjdk.jol.vm.VM().details()
  • 把高频访问的字段(如 volatile int state)和相邻字段尽量凑成 64 字节缓存行内,避免跨行;但别手动插 padding 字段——JVM 不保证它们不被重排
  • 子类字段永远排在父类字段之后,哪怕父类字段是 long、子类是 int

对齐填充不是凑整数,而是对齐 CPU 缓存行

对象总大小必须是 8 字节的整数倍,这是 JVM 的硬性要求,不是为了“好看”。真正关键的是:现代 CPU 以 64 字节缓存行为单位加载内存。如果两个频繁修改的变量落在同一缓存行,即使逻辑无关,也会因总线锁导致性能陡降(false sharing)。JVM 的对齐填充只解决前者(8 字节对齐),后者得靠程序员干预。

性能影响明显:在高并发计数器场景,未隔离的 long counter 可能比加了 7 个 long p0..p6 填充的版本慢 3–5 倍。

  • 不要以为加了 transient 就能跳过对齐——它只影响序列化,不影响内存布局
  • java.lang.Thread 类内部用了 @Contended 注解(需 -XX:+UnlockExperimentalVMOptions -XX:+RestrictContended)来强制字段独占缓存行,这是比手写 padding 更可靠的方案(JDK 8+)
  • 数组对象额外有 4 字节的 length 字段,所以 new int[0] 占 16 字节(对象头 12 + length 4),而 new long[0] 也是 16 字节,不是 12

32 位 vs 64 位 JVM 下对象大小差异在哪

差别集中在两处:对象头里的 Class Pointer 和所有引用类型字段。64 位 JVM 默认引用占 8 字节,32 位占 4 字节;但只要开启 -XX:+UseCompressedOops(JDK 7u40+ 默认开启),且堆 ≤ 32GB,引用就压成 4 字节——此时对象头从 16 字节(64 位无压缩)变成 12 字节,普通对象内存占用接近 32 位 JVM。

容易踩的坑:本地开发用默认配置(堆小、压缩开启),上线却配了 40GB 堆但忘了关压缩或没意识到已失效,结果对象头涨回 16 字节,引用变 8 字节,集合类内存暴增 30%+。

  • jstat -gc <pid></pid>OC(old capacity)和 OU(old used)变化趋势,突增可能就是压缩失效了
  • -XX:+PrintCompressedOopsMode 启动时会打印压缩是否生效及基址,务必检查
  • 数组引用(如 String[])同样受压缩影响,但 byte[] 这种 primitive 数组不涉及引用,大小不变

对象布局不是静态图纸,它是 JVM、CPU 架构、GC 策略和代码行为共同作用的动态结果。光看《深入理解 JVM》里的图不够,得用 JOL 验证、用 jstat 观察、在 GC 日志里找线索——尤其是当对象大小和预期差 4 或 8 字节时,八成是压缩开关或字段重排序在捣鬼。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

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

730

2023.08.02

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

587

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

104

2025.10.23

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

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

358

2023.11.13

java boolean类型
java boolean类型

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

37

2025.11.30

string转int
string转int

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

730

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

564

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

213

2025.08.29

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

23

2026.02.13

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.5万人学习

C# 教程
C# 教程

共94课时 | 9.3万人学习

Java 教程
Java 教程

共578课时 | 64.8万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号