用VisualVM堆转储计算Java对象的内存使用率与理论方法不匹配

时间:2018-12-03 16:31:43

标签: java memory jvm jvm-hotspot

我所提出的只是一个简单的问题。根据Java文档和许多有关Java内存对象布局的文章,如果我们有一个带有一个int变量的类,则该对象的总内存消耗将为:

  • 8字节为标题
  • int的4个字节
  • 4字节填充(将总数取整为8字节的倍数)= 16 字节总数
public class Ab {        
    int b;
}

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

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

2 个答案:

答案 0 :(得分:5)

使用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)

答案 1 :(得分:1)

根据热点文档中的“对象标头布局”部分: https://wiki.openjdk.java.net/display/HotSpot/CompressedOops

“对象标头包含一个本机大小的标记字,一个克拉斯字,一个32位长的字(如果对象是数组),一个32位间隙(如果对齐规则要求),然后零个或多个实例字段,数组元素或元数据字段。

所以这意味着您的情况看起来像这样:

  • 标记字为8字节(在64位体系结构上为8字节)
  • klass字的4个字节(因为默认情况下使用压缩的oops)
  • 8字节间隔(即int字段存储的地方)