new object()在64位hotspot jvm(开启指针压缩)下实际占16字节:12字节对象头(mark word+class pointer)+4字节对齐填充;关闭指针压缩则为24字节。

Java空对象占多少字节?new Object() 真的只占 8 字节吗?
不是。在主流 HotSpot JVM(64 位、开启指针压缩)下,new Object() 实际占用 16 字节:12 字节对象头(Mark Word + Class Pointer)+ 4 字节对齐填充。对象头本身不固定——关闭指针压缩后 Class Pointer 从 4 字节涨到 8 字节,对象头变成 16 字节,总大小就变成 24 字节。
常见错误是直接查文档或网上“Object 占 8 字节”的过时说法,没考虑 JVM 版本、是否启用 -XX:+UseCompressedOops、以及内存对齐强制补齐规则。
- 对象大小必须是 8 字节的整数倍,不足则填充(padding)
- JDK 8 及以后默认开启指针压缩;JDK 15+ 开始逐步废弃,但 64 位小堆仍默认开
- 用
java -XX:+PrintCommandLineFlags可确认是否启用压缩 - 精确测量要用
Instrumentation.getObjectSize(),不能靠手动加字段估算
一个 int 字段会让对象变大多少?Integer 呢?
加一个 int 字段,在指针压缩开启时,对象从 16 字节 → 24 字节:12 字节头 + 4 字节 int + 4 字节对齐填充(12+4=16,未满 24,但 HotSpot 对齐粒度是 8,所以补到 24)。但如果字段是 Integer(引用类型),只增加 4 字节引用(压缩后),对象仍是 24 字节——实际对象实例另存堆上,不计入当前对象布局。
容易踩的坑是误以为 Integer i = 1 的值内联进对象里。它只是个指向堆中 Integer 实例的指针,而那个实例自己还有 16 字节开销(头 + int + padding)。
立即学习“Java免费学习笔记(深入)”;
-
boolean/byte单独存在也占 4 字节(对齐需要),和int一样 - 多个小字段会打包进同一缓存行,比如
byte a; byte b; byte c;还是占 4 字节(+ padding 后共 24) - 字段声明顺序影响布局:JVM 会按大小重排(
long/double→int→short/byte→boolean→ 引用),但子类字段一定在父类之后
为什么 ArrayList 初始容量为 0 时,new ArrayList() 却不是空对象?
因为 ArrayList 有 3 个字段:Object[] elementData(4 字节)、int size(4 字节)、int modCount(4 字节),加上 12 字节对象头,共 24 字节——和单 int 对象一样大。但关键在于:elementData 默认指向共享的空数组 EMPTY_ELEMENTDATA,这个数组对象本身另占 16 字节(Object[] 是对象,不是栈上值)。
所以“空”是逻辑上的,内存上至少有两个对象:ArrayList 实例 + 一个共享的空数组实例。别被构造函数没传参就当成零开销。
- 用
new ArrayList(0)也会分配新数组(非共享),多出一次 16 字节分配 - 频繁创建空
ArrayList会触发大量小对象分配,GC 压力比想象中高 - 如果确定只读且为空,复用
Collections.emptyList()(返回不可变单例,0 额外对象)
怎么验证自己代码里的对象真实大小?别信 IDE 的“估算”
IDE 显示的“size”通常是基于字段粗略加总,没算对象头、没考虑对齐、更不处理继承链和 JVM 内部优化(如扁平化嵌套记录类)。唯一靠谱方式是走 JVM Instrumentation API。
步骤很简单:写一个 agent,调用 Instrumentation.getObjectSize(),但注意它只返回“浅大小”(shallow size),不含引用指向的对象。要总内存占用得递归遍历——这时候建议直接用 JOL(Java Object Layout)工具,一行命令就能出结构图。
- 用 JOL:
mvn compile exec:java -Dexec.mainClass="org.openjdk.jol.vm.VM" # 查 JVM 参数,再运行GraphLayout.parseInstance(obj).toPrintable() -
getObjectSize()在 JDK 9+ 需通过--add-exports java.base/jdk.internal.vm=ALL-UNNAMED才能访问 - 同一对象在不同 GC 算法下布局可能微调(如 ZGC 引入元数据区),但对象头+字段+对齐规则不变
真正难的不是算单个对象,而是理解字段排列如何影响 CPU 缓存行利用率——比如把热点字段和冷字段混在一起,会导致伪共享(false sharing),这种问题光看字节数根本发现不了。









