我碰到一个面试问题:
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,正确的答案是:
关于java - Java中32位和64位系统中对象大小的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24836854/