我目前正在设计一个数据结构,我试图将内存消耗保持在最低限度。我有一些实例变量可能为空,具体取决于节点在 Trie 中的位置。我开始创建单独的类(一个有实例变量,一个没有),这样我就不会用空引用浪费大量空间......但后来我开始想知道 jvm 是如何工作的. 如果对象引用为空,它是否仍会占用完整的 8 个字节(假设 x64 架构),或者它是否有更优化的方式来存储空引用?
4 回答
我几乎可以肯定 JVM 将使用与null
其他任何参考一样多的空间。如果您有一个具有 3 个引用字段的对象,并且您将中间的那个无效,我认为任何虚拟机都无法移动第三个并保存 4 或 8 个字节(然后当您更改到null
别的东西,它必须再次移动东西)。如果这在技术上是可行的,那就不值得了——额外的计算成本和代码复杂性会扼杀任何潜在的收益。此外,部分由于 C 的传统,在大多数机器上,按位等于 0 的指针在非常低的级别上作为 NULL 工作,因此null
引用具有相当明显的表示。
在 Oracle/Sun JDK上,如果您的堆小于 16 GB(无论引用是否存在),您可以使用-XX:+UseCompressedOopsnull
命令行参数在 64 位上进行 4 个字节的引用而不是 8 个字节。
答案是肯定的,它仍然使用必要的字节。在 Java 中,null 只是一个引用可以具有的值。这意味着引用什么都没有。在这种情况下,您仍然会占用参考空间。这是 32 位系统上的 4 个字节或 64 位系统上的 8 个字节。
请参见空变量是否需要内存空间
类和超类也使用一些字节。
如果你真的想避免大部分内存使用,我建议使用FlyWeight模式
(想法:重用相同的不可变对象;让工厂创建和缓存它们)。
您的代码变得有点复杂,这很糟糕。但是你可以节省很多内存。
另一种选择是处理更简单的类型(不是对象)。但是,它不太实用,您必须在外部对数据进行所有操作……所以我更喜欢 FlyWeight。
我们可以应用简单的数学运算:假设您有一个具有 type 字段的对象,int
在任何架构上都是 4 个字节,它可以是未定义的(这取决于用例该字段必须取什么值,您可以理解它是未定义的)。现在,如果已定义,则使用 4 个字节。如果未定义,则浪费 4 个字节。
假设您将其包装到对象中。现在,如果定义了该字段,它将使用 4 或 8 个字节(取决于 JVM 位数和使用 开启或关闭的指针压缩-XX:+UseCompressedOops
)作为指针。具有单个 4 字节字段的对象将消耗 16 字节,无论位数如何(对象在 32 位和 64 位 Java 运行时都将占用 16 字节,因为它包含 8 或 12 字节的对象头和 4 字节的值,并且使用的内存对齐最接近的 8 个字节)。
总而言之,如果您坚持使用原语,您将使用 4 个字节。如果您将单个包装int
到一个对象中,如果该字段具有值,您将使用 20 或 24 个字节;如果值为空,则为 4 或 8 个字节。