我知道如何通过添加三个部分来计算Java对象的内存大小:标头+属性+引用。
我还知道Java数组也是一个对象。
但是当我读到《Understanding the JVM Advanced Features and Best Practices, Second Edition》时,它说Java数组的头部由三部分组成;标记字、类指针和数组长度。
在 Hotspot 64 位 JVM 中它始终是 24 字节。
但是在32位JVM中,如何计算Java数组的内存大小呢?
我希望你们能给我一些 Java 代码示例来告诉我如何计算对象的内存大小,而不限于数组对象。
实际的对象大小是特定于实现的,甚至不要求对象所需的大小在其生命周期内保持不变。
There’s wiki.openjdk.java.net 上的一篇文章 https://wiki.openjdk.java.net/display/HotSpot/CompressedOops#CompressedOops-Objectheaderlayout陈述:
对象标题布局
对象头由一个本机大小的标记字、一个 klass 字、一个 32 位长度字(如果对象是数组)、一个 32 位间隙(如果对齐规则需要)以及零个或多个实例组成字段、数组元素或元数据字段。 (有趣的琐事:Klass 元对象在 klass 单词之后立即包含一个 C++ vtable。)
间隙字段(如果存在)通常可用于存储实例字段。
如果 UseCompressedOops 为 false(并且始终在 ILP32 系统上),则 mark 和 klass 都是本机机器字。对于阵列,间隙始终存在于 LP64 系统上,并且仅存在于 ILP32 系统上具有 64 位元素的阵列上。
如果 UseCompressedOops 为 true,则 klass 为 32 位。非数组在 klass 后面紧接着有一个间隙字段,而数组在 klass 后面紧接着存储长度字段。
您计算对象大小的“标题+属性+引用”不正确。首先,对对象的引用不属于引用对象的对象大小。可以有任意数量的对同一对象的引用,但这些引用根本不必位于堆内存或 RAM 中,因为优化的代码可以纯粹通过 CPU 寄存器访问对象。
此外,正如上面引用中所暗示的,对齐规则使得字段所需的内存计算变得非常重要。标头中可能存在一个间隙,如果存在适合其中的类型的字段,则该间隙可用于存储实例字段。虽然同一类的字段可能会进行排列以最小化填充,但子类必须适应超类的布局,可能会向其中添加更多字段,并且只有在具有适合类型的字段时才可能填充空白,否则,由于类层次结构的原因,可能会有更多的差距。
对于数组,您可以从引用的文章中得出,32 位 HotSpot 表示使用 12 字节的标头,除非类型是long[]
or double[]
,在这种情况下它将是 16 字节。
对于 64 位实现,UseCompressedOops
选项(默认情况下处于启用状态)允许将 64 位标记字与 32 位 klass 和 32 位长度组合到总共 16 字节的标头中。除非UseCompressedOops
关闭时,标头将为 24 字节。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)