什么决定了Java对象的大小?

时间:2011-08-14 22:26:38

标签: java memory-management

对内存中单个对象的大小有什么影响?

我知道原语和引用会,但还有什么吗? 方法的数量和长度是否重要?

4 个答案:

答案 0 :(得分:65)

这完全取决于实现,但有一些因素会影响Java中的对象大小。

首先,Java对象中字段的数量和类型肯定会影响空间使用,因为您需要至少拥有保存所有对象字段所需的存储空间。但是,由于填充,对齐和指针压缩优化,没有直接的公式可以用来精确计算以这种方式使用多少空间。

对于方法,通常说对象中的方法数量对其大小没有影响。方法通常使用名为virtual function tables(或“vtable”)的功能实现,这使得可以在恒定时间内通过基类引用调用方法。这些表通常是通过在多个对象之间共享vtable的单个实例来存储的,然后让每个对象存储一个指向vtable的单个指针。

接口方法使这个图片有点复杂,因为有几种不同的实现可能。一个实现为每个接口添加一个新的vtable指针,因此实现的接口数量可能会影响对象大小,而其他接口则不会。同样,它的实现取决于事物实际上是如何放在内存中的,因此您无法确定这是否会产生内存成本。

据我所知,目前还没有JVM的实现,其中方法的长度会影响对象的大小。通常,每个方法只有一个副本存储在内存中,然后在特定对象的所有实例之间共享代码。使用较长的方法可能需要更多内存,但不应影响类的实例的每对象内存。也就是说,JVM规范并未承诺必须如此,但我想不出一个合理的实现会为方法代码花费额外的每个对象空间。

除了字段和方法之外,许多其他因素可能会影响对象的大小。这里有几个:

根据JVM使用的垃圾收集器(或收集器)的类型,每个对象可能有额外的存储空间来保存有关对象是活动的,死的,可访问的等信息。这可以增加存储空间,但是这是你无法控制的。在某些情况下,JVM可能通过尝试将对象存储在堆栈而不是堆上来优化对象大小。在这种情况下,某些类型的对象可能甚至不存在开销。

如果使用同步,则对象可能会为其分配额外的空间,以便可以同步它。在必要时,JVM的某些实现不会为对象创建监视器,因此如果不使用同步,最终可能会有较小的对象,但您不能保证会出现这种情况。

此外,为了支持instanceof等运算符和类型转换,每个对象可能都有一些空间来保存类型信息。通常,这与对象的vtable捆绑在一起,但不能保证这是真的。

如果使用断言,某些JVM实现将在类中创建一个包含是否启用断言的字段。然后,它用于在运行时禁用或启用断言。同样,这是特定于实现的,但要记住这一点很好。

如果您的类是非静态内部类,则可能需要保存对包含它的类的引用,以便它可以访问其字段。但是,如果你最终没有使用它,JVM可能会优化它。

如果使用匿名内部类,则该类可能需要保留额外的空间来保存在其封闭范围内可见的final变量,以便可以在类中引用它们。它是特定于实现的,是将这些信息复制到类字段中还是仅存储在堆栈中,但它可以增加对象大小。

Object.hashCode()System.identityHashCode(Object)的某些实现可能需要在每个包含该哈希代码值的对象中存储额外信息,如果它无法以任何其他方式计算它(例如,如果对象可以重新定位在内存中)。这可能会增加每个对象的大小。

答案 1 :(得分:7)

向@ templatetypedef的优秀答案添加一些(公认的模糊)数据。这些数字适用于典型的最新32位JVM,但它们是特定于实现的

  • 每个对象的标头开销通常常规对象为2个字,数组为3个字。标题包括GC相关标志,以及指向对象实际类的某种指针。对于数组,需要额外的字来保存数组大小。

  • 如果您已经(直接或间接)调用某个对象上的System.identityHashCode(),并且它在GC循环中幸存下来,则添加一个额外的字来存储哈希码值。 (现代JVM使用一个聪明的技巧来避免为所有对象保留哈希码头字段...)

  • 存储分配粒度可能是多个单词;例如2。

  • 对象的字段通常是字对齐的;即他们没有包装。

  • 基本类型数组的元素是打包的,但是布尔值通常用打包形式的字节表示。

  • 引用占用4个字节作为字段和数组元素。

由于某些JVM中的指针压缩(OOPS),64位JVM的情况要复杂一些。另外,我不确定字段32或64位是否对齐。


(注意:以上是基于我在各个地方听到/读过的各种“知识渊博的人”。除了Oracle / Sun和(AFAIK)他们还没有这种信息的确切来源什么都没发表。)

答案 2 :(得分:4)

在这里查看sourceforge中的java.sizeOf:http://sizeof.sourceforge.net/

答案 3 :(得分:0)

AFAIK,在HBase源代码中,有一些关于对象大小的计算基于一些常见的已知规则,不同的字段如何占据空间。它在32位或64位操作系统中会有所不同。至少在上面的人都知道。但我没有详细研究为什么他们这样做。但他们确实在源代码中做到了。

此外,Java.lang.intrument.Intrumentation类也可以通过getObjectSize()来实现。我想开源项目也是基于它的。 在此链接中,有关于如何使用它的详细信息。 In Java, what is the best way to determine the size of an object?

作为评论。实际上我也感兴趣,如果你在源代码中这样做,最有意义的用例是什么?