Java 最小化内存使用的类设计:如果对象实例变量(非原语)为null,它是否仍使用必要的引用字节?

Java 最小化内存使用的类设计:如果对象实例变量(非原语)为null,它是否仍使用必要的引用字节?,java,memory,memory-management,jvm,Java,Memory,Memory Management,Jvm,我目前正在设计一种数据结构,在这种结构中,我试图将内存消耗降到最低。我有几个实例变量可能为null,具体取决于节点在Trie中的位置。我开始创建单独的类(有实例变量的类和没有实例变量的类),这样我就不会浪费大量的空引用空间了。。。但后来我开始怀疑jvm是如何工作的。如果对象引用为null,它是否仍然会消耗掉全部8个字节(假设为x64 arch),或者它是否有更理想的方式来存储null引用?答案是肯定的,它仍然使用必要的字节。 在Java中,null只是一个引用可以拥有的值。这意味着引用没有任何内

我目前正在设计一种数据结构,在这种结构中,我试图将内存消耗降到最低。我有几个实例变量可能为null,具体取决于节点在Trie中的位置。我开始创建单独的类(有实例变量的类和没有实例变量的类),这样我就不会浪费大量的空引用空间了。。。但后来我开始怀疑jvm是如何工作的。如果对象引用为null,它是否仍然会消耗掉全部8个字节(假设为x64 arch),或者它是否有更理想的方式来存储null引用?

答案是肯定的,它仍然使用必要的字节。 在Java中,null只是一个引用可以拥有的值。这意味着引用没有任何内容。在这种情况下,仍然会使用引用的空间。在32位系统上为4字节,在64位系统上为8字节


请参见

类和超类也使用一些字节

如果你真的想避免大部分内存使用,我建议使用FlyWeight模式

(想法:重用相同的不可变对象;让工厂创建并缓存它们)

您的代码变得有点复杂,这是不好的。但是你可以节省很多内存


另一种选择是处理更简单的类型(而不是对象)。 不过,这不太实际,您必须在数据外部执行所有操作。。。
因此,我更喜欢FlyWeight。

我几乎可以肯定,JVM在
null
引用中使用的空间与在其他引用中使用的空间一样多。如果你有一个对象,比如说3个引用字段,你把中间的一个空了,我不认为任何虚拟机都能移动第三个并保存4个或8个字节(然后,当你把<代码> null <代码>改成别的东西时,它就必须再次移动东西了)。如果这在技术上是可行的,那就不值得了——额外的计算成本和代码复杂性将扼杀任何潜在的收益。另外,部分由于C语言的传统,在大多数机器上,位等于0的指针在非常低的级别上充当NULL,因此
NULL
引用有一个相当明显的表示形式


在Oracle/Sun JDK上,如果堆小于16 GB(无论引用是否为
null
),您可以使用命令行参数在64位上引用4字节而不是8字节。我们可以应用简单的数学:假设您有一个字段类型为
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字节。

我认为对象引用仍然被分配(8字节),但没有为对象本身分配内存。但是我不知道,所以我对答案很感兴趣。这只是实现空引用的一种可能的方法。如何阻止JVM以不同的方式进行操作?