使用 VisualVM 堆转储计算 java Object 的内存使用情况与理论方法不符

Calculating the Memory Usage of java Object with VisualVM Heap Dump does not match with theoretical approach

我带着一个简单的问题来了。根据 java 文档和许多关于 java 内存 object 布局的文章,如果我们有一个 class 和一个 int 变量,则该 [= 的总内存消耗37=] 将是:

public class Ab {        
    int b;
}

public static void main(String args[]) throws InterruptedException {
    Ab ab = new AB();  
}  

我现在的问题是,当我使用 Visual vm 并查看堆转储以观察这个理论方法时,我注意到 object 的内存消耗是 20 字节而不是 16?为什么会这样?有人可以给我解释一下吗?

根据热点文档中的 "Object header layout" 部分: https://wiki.openjdk.java.net/display/HotSpot/CompressedOops

"一个对象头由一个native-sized的mark word,一个klass word,一个32位长度的word(如果对象是一个数组),一个32位的gap(如果对齐规则需要),然后是零个或多个实例字段、数组元素或元数据字段。

所以这意味着在你的情况下它看起来像这样:

  • 标记字 8 个字节(64 位架构上为 8 个字节)
  • 4 字节用于 klass 字(因为默认情况下使用压缩 oops)
  • 8 字节间隙(即存储您的 int 字段的位置)

使用 Java Object Layout 工具,我收到以下输出:

 OFFSET  SIZE   TYPE DESCRIPTION        VALUE
      0    12        (object header)    N/A
     12     4    int Ab.b               N/A

Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

并且使用 -XX:-UseCompressedOops VM 选项(禁用压缩引用):

 OFFSET  SIZE   TYPE DESCRIPTION                                VALUE
      0    16        (object header)                            N/A
     16     4    int Ab.b                                       N/A
     20     4        (loss due to the next object alignment)

Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

Java环境:

java version "11" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11+28)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode)