本文共 817 字,大约阅读时间需要 2 分钟。
最近在调研MAT和VisualVM源码实现时,发现它们计算出来的对象大小不一致,这让我感到有些困惑。为了复现这个问题,我准备了四个最简单的Java类:AAAAA、BBBBB、CCCCC和DDDDD。每个类的字段类型不同:AAAAA没有字段,BBBBB有一个int,CCCCC有一个long,DDDDD有一个String。然后,在主函数中创建了这些类的100,000个实例,并添加到四个不同的列表中。系统是64位的JDK8,使用默认的启动参数运行。
运行之后,使用jmap-dump生成dump文件,并分别用MAT和VisualVM打开。通过MAT,我发现每个ABD对象的大小都是16字节,而CCCCC的大小是24字节。然而,在VisualVM中,显示的结果与MAT差别很大。
在Hotspot中,一个对象由对象头、实例数据和对齐填充组成。对象头的大小取决于系统位数和UseCompressedOops参数。在64位系统中,开启UseCompressedOops时,对象头占用12字节,否则是16字节。实例数据的大小取决于字段的类型:原生类型的大小如上所述,引用类型则为4或8字节,根据UseCompressedOops参数决定。
对齐填充是为了确保内存分配是8字节的倍数。如果对象头和实例数据的总和不是8的倍数,就会加上填充字节。例如,A对象的对象头是12字节,加上实例数据(没有),总和是12,不是8的倍数,所以需要4字节填充,总大小16字节。B对象的对象头12字节,加上int4字节,总和16,刚好是8的倍数,不需要填充。C对象的对象头12字节,加上long8,总和20,不是8的倍数,所以需要4字节填充,总大小24字节。D对象的对象头12字节,加上引用4,总和16,刚好是8的倍数,不需要填充。
因此,VisualVM显示的问题可能是因为它没有考虑UseCompressedOops参数和对齐填充。建议使用MAT,因为它更准确。
转载地址:http://wdqfk.baihongyu.com/