java - Java中32位和64位系统中对象大小的差异

标签 java object memory memory-management jvm

我碰到一个面试问题:

class Test {
    int a ; 
    int b;
    char c;
}

此类需要多少内存对象以及为什么在以下对象上实现:

a)32位计算机

b)64位计算机

我得到的答案是:
For 32-bit: 4+4+2+8 = 18 bytes
For 64-bit: 4+4+2+16 = 26 bytes

由于分配了一些额外的内存,除了对象的正常大小外,在32位系统中为8字节,在64位系统中为16字节。

您能否对此声明提供一些解释。

附注:我也想分享我从其他来源得到的答案(不能依靠,想验证):

在32位pc对象中,比其数据成员所定义的实际obj大小多占用8个字节....在64位pc对象中,其数据成员所定义的实际obj大小比其实际对象大.....问题出现的原因...据我所知,其背后的原因是:::在32位pc中,JVM保留了前8个字节,用于引用类定义,对齐,父类(super class)和子类的空间等。 。对于64位,它为这些对象保留16个字节。.有一个公式可以计算对象在创建时需要多少堆空间,并将其计算为.....。 。浅堆大小= [对类定义的引用] +父类(super class)字段的空间+实例字段的空间+ [对齐]

您如何计算对象“自身”需要多少内存?显然有一个公式可以解决:

浅堆大小= [对类定义的引用] +父类(super class)字段的空间+实例字段的空间+ [对齐]

似乎不太有用,是吗?让我们尝试使用以下示例代码来应用公式:
class X {
  int a;
  byte b;
  java.lang.Integer c = new java.lang.Integer();
}
class Y extends X {
  java.util.List d;
  java.util.Date e;
}

现在,我们努力回答的问题是–一个Y实例需要多少浅堆大小?让我们开始计算它,假设我们使用的是32位x86体系结构:

作为起点– Y是X的子类,因此它的大小包括父类(super class)中的“某物”。因此,在计算Y的大小之前,我们先考虑计算X的浅大小。

跳到X上的计算中,前8个字节用于引用其类定义。该引用始终存在于所有Java对象中,并且被JVM用来定义以下状态的内存布局。它还具有三个实例变量–一个int,一个Integer和一个字节。这些实例变量需要堆,如下所示:

一个字节就是应该的。内存中有1个字节。
我们的32位架构中的int需要4个字节。
对整数的引用也需要4个字节。请注意,在计算保留堆时,我们还应考虑包装到Integer对象中的原语的大小,但是在此处计算浅堆时,我们在计算中仅使用4个字节的引用大小。
那么-是吗? X的浅堆=从引用到类定义的8个字节+ 1个字节(该字节)+ 4个字节(int)+ 4个字节(对Integer的引用)= 17个字节?实际上–不。现在起作用的是对齐(也称为填充)。这意味着JVM以8字节的倍数分配内存,因此如果创建X的实例,我们将分配24字节而不是17字节。

如果您可以在这里关注我们,那很好,但是现在我们尝试使事情变得更加复杂。我们不是在创建X的实例,而是在创建Y的实例。这意味着–我们可以从引用中减去8个字节到类定义和对齐方式。乍一看可能不太明显,但是–您是否注意到,在计算X的浅大小时,我们没有考虑到它也扩展了java.lang.Object,因为即使您未在其中明确声明它,所有类也会这样做。您的源代码?我们不必考虑父类(super class)的 header 大小,因为JVM足够聪明,可以从类定义本身进行检查,而不必一直将其复制到对象 header 中。

对齐方式也一样–创建对象时,您只能对齐一次,而不是在父类(super class)/子类定义的边界处对齐。因此,可以肯定地说,当创建X的子类时,您只会从实例变量继承9个字节。

最后,我们可以跳到初始任务并开始计算Y的大小。正如我们所看到的,我们已经在父类(super class)字段中丢失了9个字节。让我们看看当我们实际构造一个Y实例时将添加什么。

Y的标题引用了其类定义,占用了8个字节。与以前的相同。
日期是对对象的引用。 4字节。简单的。
该列表是对集合的引用。同样是4个字节。不重要的。
因此,除了父类(super class)中的9个字节外,我们还有8个字节的头空间,2×4个字节的数据来自两个引用(列表和日期)。 Y实例的总浅层大小为25个字节,对齐为32个字节。

最佳答案

取决于JVM。对于HotSpot JVM,正确的答案是:

  • 32位JVM:24字节 = align8(4字节mark_word + 4字节类引用+ 4 + 4 + 2字节字段数据)
  • 64位JVM -XX:+ UseCompressedOops:24字节 = align8(8字节mark_word + 4字节类引用+ 4 + 4 + 2字节字段数据)
  • 64位JVM -XX:-UseCompressedOops:32字节 = align8(8字节mark_word + 8字节类引用+ 4 + 4 + 2字节字段数据)
  • 关于java - Java中32位和64位系统中对象大小的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24836854/

    相关文章:

    java - 检查列表中的重复条目

    powershell - 为Out-GridView列添加自定义对象

    PHP将相同的xml对象键存储到不同的mysql表

    python - 理解 Python 中的对象

    C - 从特定的大范围中获取素数

    c++ - 在 C++ 中实现接口(interface)功能

    c++ - 将 16 位整数复制到两字节数组

    java - 获取数组中的一些项目

    java - Jersey 响应 HTTP 400 Bad Requests,毫 headless 绪

    java - ARM REST API 需要哪些权限