我试图了解 Java 中对象的内存占用量是多少。我阅读了这个文档和其他关于 Java 中对象和内存的文档。
但是,当我使用sizeof Java 库或 visualvm 时,我得到了两个不同的结果,其中没有一个符合我根据之前的参考 ( http://www.javamex.com ) 所期望的结果。
对于我的测试,我正在Java SE 7 Developer Preview
使用64-bits Mac
with java.sizeof 0.2.1
and visualvm 1.3.5
。
我有三个班TestObject
,,,,TestObject2
。TestObject3
public class TestObject
{
}
public class TestObject2 extends TestObject
{
int a = 3;
}
public class TestObject3 extends TestObject2
{
int b = 4;
int c = 5;
}
我的主要课程:
public class memoryTester
{
public static void main(String[] args) throws Throwable
{
TestObject object1 = new TestObject();
TestObject2 object2 = new TestObject2();
TestObject3 object3 = new TestObject3();
int sum = object2.a + object3.b + object3.c;
System.out.println(sum);
SizeOf.turnOnDebug();
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object1)));
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object2)));
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object3)));
}
}
使用 java.SizeOf() 我得到:
{ test.TestObject
} size = 16.0b
16.0b
{ test.TestObject2
a = 3
} size = 16.0b
16.0b
{ test.TestObject3
b = 4
c = 5
} size = 24.0b
24.0b
使用visualvm我有:
this (Java frame) TestObject #1 16
this (Java frame) TestObject2 #1 20
this (Java frame) TestObject3 #1 28
根据我通过 Internet 阅读的文档,因为我是 64 位的,所以我应该有一个 16 字节的对象头,对于TestObject
.
然后TestObject2
我应该为整数字段添加 4 个字节,给出 20 个字节,我应该再次添加 4 个字节的填充,总大小为 24 个字节TestObject2
。我错了吗?
继续这种方式TestObject3
,我必须为应该提供 32 个字节的两个整数字段再添加 8 个字节。
VisualVm 似乎忽略了填充,而 java.sizeOf 似乎错过了 4 个字节,就好像包含在对象头中一样。我可以用 4 个布尔值替换一个整数,它给出了相同的结果。
问题:
为什么这两个工具给出不同的结果?
我们应该有填充吗?
我还在某处读到(我没有找到链接),在一个类和它的子类之间可能有一些填充,对吗?在那种情况下,继承的类树可能会有一些内存开销?
最后,是否有一些 Java 规范/文档详细说明了 Java 正在做什么?
谢谢你的帮助。
更新:
为了回答 utapyngo 的评论,为了获取 visualvm 中对象的大小,我创建了一个堆转储,然后在“类”部分中,我检查了“实例”列之后的“大小”列。每种对象的实例数(如果为 1)。
为了回答 Nathaniel Ford 的评论,我初始化了每个字段,然后在我的主要方法中对它们进行了简单的求和以利用它们。它没有改变结果。