我试图了解Java中对象的内存占用量。我在Java中阅读了this和其他关于对象和内存的文档。
但是,当我使用sizeof Java library或visualvm时,我会得到两个不同的结果,根据之前的参考文献(http://www.javamex.com),这些结果都不会超出我的预期。
对于我的测试,我使用Java SE 7 Developer Preview
64-bits Mac
与java.sizeof 0.2.1
和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)));
}
}
我的主要课程:
{ 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
使用java.SizeOf()我得到:
this (Java frame) TestObject #1 16
this (Java frame) TestObject2 #1 20
this (Java frame) TestObject3 #1 28
使用visualvm我有:
TestObject
根据我在互联网上阅读的文件,因为我是64位的,我应该有一个16字节的对象标题,对TestObject2
来说没问题。
然后对于TestObject2
,我应该为整数字段添加4个字节,给出20个字节,我应该再添加4个字节的填充,为TestObject3
提供24个字节的总大小。我错了吗?
继续{{1}}的方式,我必须为两个整数字段添加8个字节,这应该给出32个字节。
VisualVm似乎忽略了填充,而java.sizeOf似乎错过了4个字节,好像它包含在对象头中一样。我可以用4个布尔值替换一个整数,它会得到相同的结果。
问题:
为什么这两个工具会产生不同的结果?
我们应该填充吗?
我也读过某个地方(我没找到链接),在类和它的子类之间可能有一些填充,是不是?在这种情况下,继承的类树可能会有一些内存开销吗?
最后,是否有一些Java规范/文档详细说明了Java正在做什么?
感谢您的帮助。
更新
要回答utapyngo的评论,为了获得visualvm中对象的大小,我创建了一个heapdump,然后在" Classes"第一部分检查专栏"尺寸"列"实例"之后的下一个。每种对象的实例数,如果为1。
为了回答纳撒尼尔·福特的评论,我初步化了每个玩家,然后在我的主要方法中与他们做了一个简单的总结,以利用它们。它并没有改变结果。
答案 0 :(得分:2)
是填充可能发生。堆栈上的对象也可以完全优化。只有JVM知道任何时间点的确切大小。由于这种从Java语言中近似大小的技术都倾向于不同意,因此附加到JVM的工具往往是最准确的。我所知道的在Java中实现sizeOf的三种主要技术是:
这些技巧都不准确。
如果您在v1.5上或之后在Oracle JVM上运行。然后有一种方法可以直接从Java运行时使用的C结构中读取对象的大小。对于生产来说不是一个好主意,并且错误然后你可以崩溃JVM。但是这里有一篇博文,如果你想了解它,你可能会感兴趣:http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/
关于Java实际正在做什么的文档,这是JVM特定的,特定于版本的,也可能是特定于配置的。每个实现都可以以不同方式自由处理对象例如,即使在完全优化对象的范围内,也不会在堆上自由地分配未从堆栈中传出的对象。有些JVM甚至可以设法将对象完全保留在CPU寄存器中。这不是你的情况,但我把它作为一个例子来说明为什么获得Java对象的真实大小是棘手的。
所以最好采取任何尺寸的价值,你得到一点点盐,并把它作为一个指南'仅测量。