64位VM未开启指针压缩导致-8内存对齐的疑问
问题
使用JOL工具分析对象内存布局时,配置64位VM未开启指针压缩,运行测试代码后结果显示出现-8内存对齐损失,无法理解该现象成因。
Maven依赖(pom.xml)
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.10</version> </dependency>
测试代码
public class MyObjectData { private int i=66; private long l=6L; private String string=new String("aaaa"); } public class ObjectTest { @Test public void test1() { Layouter l; // 64位VM,未开启指针压缩 l = new HotSpotLayouter(new X86_64_DataModel()); System.out.println("***** " + l); System.out.println(ClassLayout.parseInstance(new MyObjectData(), l).toPrintable()); System.out.println("==============================================="); } }
运行结果
OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 01 23 01 f8 (00000001 00100011 00000001 11111000) (-134143231) 12 4 (object header) 42 00 00 00 (01000010 00000000 00000000 00000000) (66) 16 8 long MyObjectData.l 6 24 4 int MyObjectData.i 66 28 4 (alignment/padding gap) 32 8 java.lang.String MyObjectData.string (object) 40 -8 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 4 bytes internal + -8 bytes external = -4 bytes total
分析与解答
这个负的外部对齐损失是JOL特有的统计逻辑,本质不是真的“损失”,而是表示当前对象的末尾刚好满足下一个对象的对齐要求,省去了后续对象需要的对齐填充空间,相当于空间收益。
具体拆解:
- 64位无指针压缩的HotSpot对齐规则:对象起始地址必须是8字节的倍数,单个对象的总大小也会对齐到8字节的倍数。
- 当前对象内存布局细节:
- 对象头占16字节(无指针压缩时,Mark Word+Klass Pointer合计16字节)
long l占8字节(偏移到16-24字节)int i占4字节(偏移到24-28字节)- 内部填充4字节(偏移28-32字节):为了让后续的8字节引用类型字段(
string)能对齐到8字节边界 String string引用占8字节(偏移32-40字节)
- 负损失的由来:
JOL的“external loss”(外部损失)统计的是当前对象结束后,下一个对象为了满足对齐要求需要额外填充的字节数。如果当前对象的总大小是8的倍数(这里是40字节),下一个对象可以直接从40字节地址开始,不需要任何填充。JOL用-8表示:相比“当前对象结束在非对齐地址,下一个对象需要填充8字节”的情况,现在节省了8字节空间,所以用负数标识这种“反向损失”(即收益)。
另外,结果里的4字节内部损失是int i之后填充的4字节,用来保证后续8字节引用字段的对齐,属于正常的内部对齐填充。
内容的提问来源于stack exchange,提问作者ami who
相关产品推荐
相关产品推荐

