对齐填充是jvm为保证对象起始地址8字节对齐而强制添加的占位字节,旨在提升cpu缓存访问效率、避免伪共享并优化数组内存布局,而非单纯凑整。

对齐填充不是为了“凑整数”,而是让对象在内存中站得稳、读得快、并发时不出乱子。它直接决定字段如何落进缓存行,影响单线程访问效率和多核竞争行为。
让对象起始地址对齐到硬件边界
CPU访问内存以缓存行为单位(通常是64字节),JVM则按8字节对齐管理对象。如果一个对象起始地址不是8的倍数,不仅可能跨缓存行,还会导致HotSpot在分配时额外插入填充字节来补足——这不是浪费,是强制对齐的必要代价。
- 对象头(Mark Word + 类型指针)通常占12或16字节,本身不一定是8字节倍数
- 实例数据部分若总长为20字节,加上对象头12字节得32字节 → 已对齐,无需填充
- 若实例数据为21字节,则12+21=33 → 补7字节 → 总大小40字节,确保起始地址满足8字节对齐
控制字段分布,提升缓存局部性
字段声明顺序直接影响编译器如何插入填充。JVM会按字段类型大小重排(如long优先于int),但C++等语言严格按声明顺序布局。无论哪种,目标都是让高频一起访问的字段尽量落在同一缓存行内。
- 把x/y/z坐标、timestamp/seqno这类逻辑组合字段连续放置,减少跨行读取
- 避免小字段(如byte、boolean)夹在大字段(如long、double)中间,否则会触发大量填充
- 示例:char a; long b; char c; → a后需7字节填充才能让b对齐;改为long b; char a; char c; → 仅末尾补6字节,紧凑且b与a/c更可能共处一行
隔离热点字段,防止伪共享
当多个线程频繁修改同一缓存行内的不同字段时,L1缓存会反复失效并触发总线同步——这就是伪共享。对齐填充可主动把关键字段“锁”进独立缓存行。
- 用alignas(64)修饰结构体,使其独占一个缓存行
- 在volatile计数器前后各加32字节填充,确保它不与邻近字段共享缓存行
- Java中可用@Contended(配合-XX:-RestrictContended)实现类似效果
支撑数组内存布局,优化遍历效率
对象数组(如new MyObj[1000])要求每个元素起始地址都对齐。若单个对象大小不是8的倍数,相邻对象之间就会被迫插入额外间隙。
- 对象总大小32字节 → 数组中每项占32字节 → 每个64字节缓存行可存2个对象
- 对象总大小40字节 → 每项占40字节 → 同一缓存行只能存1个,预取效率下降,页内存利用率降低
- 压缩指针(-XX:+UseCompressedOops)可将对象头从16字节减至12字节,更容易使整体大小落入8字节倍数,间接减少填充需求











