什么决定了Java对象的大小?
什么有助于内存中的单个对象的大小?
我知道原始文献和参考文献可以,但还有其他的吗? 方法的数量和长度是否重要?
这完全依赖于实现,但是有一些因素会影响Java中的对象大小。
首先,Java对象中的字段的数量和types肯定会影响空间的使用,因为你需要至less有足够的存储空间来保存所有对象的字段。 但是,由于填充,alignment和指针压缩优化,因此没有直接的公式可用于精确计算以这种方式使用多less空间。
至于方法,一般来说对象中的方法数量对其大小没有影响。 方法通常使用一个称为虚拟函数表 (或“vtables”)的特性来实现,这些特性使得可以通过基类引用在不变的时间内调用方法。 这些表通常是通过在多个对象间共享单个vtable实例来存储的,然后让每个对象存储一个指向vtable的指针。
接口方法稍微复杂一点,因为有几种不同的实现可能。 一个实现为每个接口添加一个新的vtable指针,所以实现的接口数量可能会影响对象的大小,而另一些则不会。 再一次,它的实现依赖于事情是如何在内存中实际放在一起的,所以你不能确定这是否会产生内存成本。
就我所知,目前没有JVM的实现,其中方法的长度影响对象的大小。 通常情况下,每个方法只有一个副本存储在内存中,然后代码在特定对象的所有实例中共享。 有更长的方法可能需要更多的总内存,但不应该影响类的实例的每个对象的内存。 也就是说,JVM规范并没有做出这样的承诺,但是我不能想到一个合理的实现,会为方法代码耗费每个对象的额外空间。
除了领域和方法之外,许多其他因素可能会影响对象的大小。 这里有几个:
根据JVM所使用的垃圾收集器(或收集器)的types,每个对象可能有额外的存储空间来存储有关对象是活的,死的还是可到达的等信息。这可以增加存储空间,但是它已经超出你的控制。 在某些情况下,JVM可能会通过尝试将对象存储在堆栈而不是堆中来优化对象大小。 在这种情况下,对于某些types的对象甚至可能不存在开销。
如果使用同步,对象可能会分配额外的空间,以便可以同步。 JVM的某些实现在有必要时不会为对象创build监视器,所以如果不使用同步,最终可能会得到较小的对象,但不能保证这将是事实。
此外,为了支持像instanceof
和types转换这样的操作符,每个对象可能有一些空间来保存types信息。 通常情况下,这是与对象的vtable绑定,但不能保证这是真实的。
如果使用断言,一些JVM实现将在您的类中创build一个包含是否启用断言的字段。 然后这用于在运行时禁用或启用断言。 再一次,这是针对具体实现的,但是要记住是很好的。
如果你的类是一个非静态的内部类,它可能需要持有对包含它的类的引用,以便它可以访问它的字段。 但是,如果你永远不会使用这个,JVM可能会优化这个。
如果使用匿名内部类,则该类可能需要保留额外的空间以容纳在其封闭范围内可见的final
variables,以便可以在类中引用它们。 它是特定于实现的,无论这些信息是复制到类字段还是只存储在本地堆栈中,但是可以增加对象的大小。
Object.hashCode()
或System.identityHashCode(Object)
某些实现可能需要额外的信息存储在包含该哈希代码的值的每个对象中,如果它不能以任何其他方式计算它(例如,如果该对象可以在内存中重新定位)。 这可能会增加每个对象的大小。
给@ templatetypedef的优秀答案添加一些(不可否认的)数据。 这些数字适用于典型的最新32位JVM,但它们是特定于实现的 :
-
每个对象的标题开销通常是 2个字对于一个普通对象和3个字对于一个数组。 头部包含GC相关的标志,以及某种types的指向对象实际类的指针。 对于数组,需要额外的单词来保存数组的大小。
-
如果你直接或间接调用了一个对象上的
System.identityHashCode()
,并且它已经在一个GC循环中生存了下来,然后添加一个额外的单词来存储哈希码值。 (现代的JVM使用一个聪明的技巧来避免为所有的对象保留一个hashcode头字段…) -
存储分配粒度可以是单词的倍数; 例如2。
-
对象的字段通常是字alignment的; 即他们没有包装。
-
原始types数组的元素是打包的,但是布尔值通常用包装forms的字节表示。
-
引用占用4个字节,既作为字段又作为数组元素。
由于某些JVM中的指针压缩(OOPS),事情对于64位JVM更复杂一些。 另外,我不确定字段32或64位是否alignment。
(注意:以上是基于我在不同的“知识渊博的人”所听到/读过的东西,除了Oracle / Sun,还没有这种信息的确切来源,(AFAIK)他们还没有发表任何东西。)
在这里查看sourceforge中的java.sizeOf: http ://sizeof.sourceforge.net/
AFAIK,在HBase源代码中,根据一些已知规则,对不同的字段占用空间有一些关于对象大小的计算。 这在32位或64位操作系统上会有所不同。 至less以上的人都知道。 但是我没有看到细节,为什么他们这样做。 但他们真的在源代码中做到了。
此外,Java.lang.intrument.Intrumentation类也可以通过getObjectSize()来完成。 我猜这个开源项目也是基于它的。 在这个链接中,有详细的使用方法。 在Java中,确定对象大小的最佳方法是什么?
作为评论。 其实我也有兴趣,如果你在源代码中做,那么最有意义的用例是什么?