null引用不占堆内存,仅占栈中4或8字节;空Object实例在64位JVM默认下占16字节,含对象头与对齐填充;空数组如new Object[0]占24字节,含length字段。

在Java中,当声明一个对象引用但未初始化时,该引用指向null;而创建一个空对象实例(如new Object())则会在堆内存中分配实际空间。二者在内存模型中的表现存在本质差异。以下是关于null引用与空对象实例内存占用的详细分析:
一、null引用的内存占用
null是一个特殊的字面量,表示对象引用不指向任何堆内存地址。它本身不是对象,也不占用堆空间,仅作为引用类型的默认值存储在变量所在的位置(栈帧或对象字段中)。其大小取决于JVM对引用的实现方式。
1、在32位JVM上,普通对象引用通常为4字节,null即以全0比特模式填充该4字节空间。
2、在64位JVM上,若未启用压缩指针(-XX:-UseCompressedOops),对象引用为8字节,null对应8字节全0。
立即学习“Java免费学习笔记(深入)”;
3、在64位JVM上,若启用压缩指针(默认开启),对象引用被压缩为4字节,null仍以4字节全0表示。
二、空对象实例的内存占用(以Object为例)
调用new Object()会触发JVM在堆中分配一个最简对象实例。该实例包含对象头(mark word + klass pointer)和可能的对齐填充,不含实例字段。其大小由JVM参数及平台决定。
1、在HotSpot JVM中,使用默认参数(-XX:+UseCompressedClassPointers -XX:+UseCompressedOops)的64位系统上,Object实例占用16字节:其中8字节mark word,4字节klass pointer,剩余4字节为对齐填充(保证16字节边界对齐)。
2、在禁用压缩指针的64位JVM中,Object实例占用24字节:8字节mark word,8字节klass pointer,8字节对齐填充。
3、在32位JVM中,Object实例占用8字节:4字节mark word,4字节klass pointer,无需额外填充(天然8字节对齐)。
三、数组类型空实例的内存占用
空数组(如new int[0]或new Object[0])是实际分配的对象,具备完整对象头与长度字段,因此比普通Object实例多出一个用于存储数组长度的4字节字段。
1、new Object[0]在默认64位JVM下占用24字节:16字节基础对象头结构 + 4字节length字段 + 4字节对齐填充。
2、new int[0]在相同环境下同样占用24字节:对象头16字节 + length字段4字节 + 对齐填充4字节;注意其elements区域长度为0,不额外分配元素空间。
3、在32位JVM中,new Object[0]占用12字节:8字节对象头 + 4字节length字段,无需填充。
四、验证内存占用的实验方法
可通过JOL(Java Object Layout)工具直接观测对象内存布局,该工具利用Unsafe获取底层内存信息,结果可靠且与JVM实际行为一致。
1、添加Maven依赖:引入org.openjdk.jol:jol-core:0.17及以上版本。
2、编写测试代码:调用Instrumentation.getObjectSize()或直接使用new org.openjdk.jol.vm.VM().details()输出布局。
3、运行时需添加JVM参数:-XX:+UseCompressedOops -XX:+UseCompressedClassPointers(确保与生产环境一致)。
五、对象字段对齐与填充的影响
JVM要求对象起始地址按8字节对齐,且对象总大小必须是8字节的整数倍。当对象头与字段总和不足8字节倍数时,自动追加填充字节,导致看似“空”的对象实际占用更多空间。
1、定义class Empty {}与class OneByte { byte b; }在默认64位JVM下均占用16字节,因前者无字段仍需对齐,后者1字节+填充15字节。
2、class EightBytes { long l; }占用16字节:8字节对象头 + 8字节字段,恰好满足对齐,无需额外填充。
3、class NineBytes { long l; byte b; }占用24字节:8字节头 + 8字节long + 1字节byte + 7字节填充。











