首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java对象内存占用- Visualvm和java.sizeOf度量

Java对象内存占用- Visualvm和java.sizeOf度量
EN

Stack Overflow用户
提问于 2013-03-19 02:32:49
回答 1查看 2.6K关注 0票数 8

我试图了解Java中对象的内存占用情况。我用Java阅读了关于对象和内存的和其他文档。

然而,当我使用Java库的规模或visualvm时,我会得到两种不同的结果,其中没有一种结果能达到我根据前面的引用(http://www.javamex.com)所能期望的结果。

在我的测试中,我在带有Java SE 7 Developer Previewvisualvm 1.3.564-bits Mac上使用java.sizeof 0.2.1

我有三门课,TestObjectTestObject2TestObject3

代码语言:javascript
复制
public class TestObject
{

}

public class TestObject2 extends TestObject
{
    int a = 3;
}

public class TestObject3 extends TestObject2
{
    int b = 4;
    int c = 5;
}

我的主修班:

代码语言:javascript
复制
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(),我得到:

代码语言:javascript
复制
{ 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

在视觉上,我有:

代码语言:javascript
复制
this (Java frame)   TestObject  #1  16
this (Java frame)   TestObject2 #1  20
this (Java frame)   TestObject3 #1  28

根据我在互联网上读到的文档,由于我是64位的,我应该有一个16字节的对象头,TestObject是可以的。

然后,对于TestObject2,我应该为整数字段添加4个字节,给出20个字节,我应该再次添加4个字节的填充,使TestObject2的总大小为24个字节。我说错了吗?

对于TestObject3来说,继续这种方式,我必须为两个整数字段多增加8个字节,这应该是32个字节。

VisualVm似乎忽略了填充,而java.sizeOf似乎遗漏了4个字节,就好像在对象头中包含了一样。我可以用4个布尔值来替换一个整数,结果是一样的。

问题:

为什么这两种工具给出了不同的结果?

我们应该有垫子吗?

我还在某个地方读到(我没有找到链接),在类和它的子类之间可能有一些填充,对吗?在这种情况下,继承的类树可能会有一些内存开销?

最后,是否有一些Java规范/文档详细说明了Java正在做什么?

谢谢你的帮助。

更新:

为了回答utapyngo的注释,为了在visualvm中获取对象的大小,我创建了一个堆转储,然后在"Classes“部分中,在列”实例“之后检查列" size”。每种对象的实例数(如果为1)。

为了回答Nathaniel的评论,我初始化了每个字段,然后在我的main方法中对它们做了一个简单的求和,以利用它们。它并没有改变结果。

EN

回答 1

Stack Overflow用户

发布于 2013-03-19 08:28:18

是的,填充物可能会发生。堆栈上的对象也有可能被完全优化。只有JVM知道任何时间点的确切大小。因此,在Java语言中近似大小的技术都是不同的,但是附加到JVM的工具往往是最精确的。我知道在Java中实现sizeOf的三种主要技术是:

  1. 序列化对象并返回这些字节的长度(明显错误,但对于相对比较有用)
  2. 列表项反射,以及在对象上找到的每个字段的硬编码大小常数。可以对其进行调优以达到一定的精度,但是JVM中的更改和JVM可能做的或不做的填充会抛出它。
  3. 列表项创建对象的负载,运行gc并比较jvm堆大小的变化

这些技术都不准确。

如果您正在Oracle JVM上运行,则在v1.5上或之后运行。然后有一种方法可以直接从Java运行时使用的C结构中读取对象的大小。对于生产来说,这不是一个好主意,如果你弄错了,那么你就可以让JVM崩溃了。但是这里有一篇博客文章,如果你想试一试的话,你可能会觉得很有趣:http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/

至于Java实际在做什么的文档,也就是JVM特定的、版本特定的和潜在的配置特定的。每个实现都可以以不同的方式处理对象。例如,即使在完全优化对象的范围内,没有从堆栈中传递出去的对象也是免费的,不能在堆上分配。有些JVM甚至可以将对象完全保存在CPU寄存器中。这里不是您的情况,但我把它作为一个例子,说明为什么要获得Java对象的真正大小是很棘手的。

所以最好把任何sizeOf值,你得到的一点点盐,并把它作为一个“指南”的测量。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15490561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档