繁体   English   中英

什么决定了 Java object 的大小?

[英]What determines Java object size?

是什么影响了 memory 中单个 object 的大小?

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

这完全取决于实现,但有几个因素会影响 Java 中的 object 大小。

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

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

接口方法使这幅图有点复杂,因为有几种不同的实现可能。 一种实现为每个接口添加了一个新的 vtable 指针,因此实现的接口数量可能会影响 object 大小,而其他实现则不会。 同样,它的实现取决于 memory 中事物的实际组合方式,因此您无法确定这是否会产生 memory 成本。

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

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

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

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

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

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

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

If you use an anonymous inner class, the class may need to have extra space reserved to hold the final variables that are visible in its enclosing scope so that they can be referenced inside the class. 是否将此信息复制到 class 字段或仅存储在本地堆栈中是特定于实现的,但它可以增加 object 的大小。

Some implementations of Object.hashCode() or System.identityHashCode(Object) may require extra information to be stored in each object that contains the value of that hash code if it can't compute it any other way (for example, if the object可以在内存中重定位)。 这可能会增加每个 object 的大小。

为@templatetypedef 的出色答案添加一些(不可否认的模糊)数据。 这些数字适用于典型的近期 32 位 JVM,但它们是特定于实现的

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

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

  • 存储分配粒度可以是字的倍数; 例如 2。

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

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

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

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


(注意:以上内容基于我在各个地方从各种“知识渊博的人”那里听到/读到的内容。除了 Oracle / Sun 和(AFAIK)他们还没有发布之外,这种信息没有明确的来源任何事物。)

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

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

此外,Java.lang.intrument.Intrumentation Class 也可以通过 getObjectSize() 来实现。 我猜这个开源项目也是基于它的。 在这个链接中,有如何使用它的详细信息。 在 Java 中,确定 object 大小的最佳方法是什么?

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM