new Object() 在 JVM 中到底占多大内存?
在美团、阿里等大厂的面试中,“一个 Object 对象占多少内存”是一个极其高频的题目。很多候选人认为这是一个考察“背诵能力”的冷门知识,但实际上,它考察的是你对 JVM 内存模型、对象布局以及 CPU 架构的深度理解。今天,我们就来彻底拆解这个看似简单却暗藏玄机的技术点。
一、 为什么我们要纠结这几个字节?
在日常业务开发中,我们很少关注一个对象具体占用了 16 字节还是 24 字节。但在高并发、高吞吐的场景下(如亿级流量的电商大促、海量数据的实时计算),内存就是金钱,内存就是性能。
理解对象的内存布局,是进行JVM 调优、排查内存溢出(OOM)以及设计高性能缓存组件的基石。
那么,当我们敲下 new Object() 这行代码时,JVM 堆内存中究竟发生了什么?
二、 庖丁解牛:Java 对象的内存布局
在 HotSpot 虚拟机中,一个对象在内存中的存储布局可以分为三个部分:
- 对象头(Header);
- 实例数据(Instance Data);
- 对齐填充(Padding)。
为了更直观地理解,看下图:

1. 对象头(Header)—— 对象的“身份证”
对象头是对象最核心的部分,它包含两类信息:
Mark Word(标记字段)
-
- 这是对象最“忙碌”的部分。它存储了对象的运行时数据,如:哈希码(
HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID 等。 - 在 64 位虚拟机中,Mark Word 占用 8 字节。
- 这是对象最“忙碌”的部分。它存储了对象的运行时数据,如:哈希码(
- Klass Pointer(类型指针)
-
- 对象指向它的类元数据的指针,JVM 通过这个指针来确定这个对象是哪个类的实例。
- 它的长度取决于是否开启了指针压缩(CompressedOops)。
2. 实例数据(Instance Data)—— 对象的“血肉”
这是对象真正存储有效信息的地方,即我们在代码中定义的各种字段(int, boolean, reference 等)。
- 对于
new Object()来说,因为Object类没有任何字段,所以这部分大小为 0。
3. 对齐填充(Padding)—— 强迫症的“占位符”
这是最容易被忽视的一点。HotSpot 虚拟机的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍。
- 换句话说,任何对象的大小都必须是 8 的倍数。
- 如果对象头 + 实例数据不是 8 的倍数,JVM 就会用空白数据填充,直到补齐。
三、 深度计算:new Object() 到底多大?
环境假设:我们目前绝大多数服务器都是 64 位 JVM。我们将分两种主要情况讨论。
情况 A:64 位 JVM + 开启指针压缩(默认情况)
从 JDK 1.6 update 14 开始,64 位 JVM 默认开启了指针压缩(-XX:+UseCompressedOops)。
- Mark Word:8 字节
- Klass Pointer:被压缩为 4 字节
- 实例数据:0 字节
- 当前总和:8 + 4 + 0 = 12 字节
注意:12 不是 8 的倍数!
对齐填充:JVM 必须强行填充 4 字节,使其达到 16 字节。
结论:16 字节
情况 B:64 位 JVM + 关闭指针压缩
如果你手动设置了 -XX:-UseCompressedOops,或者堆内存超过了 32GB(指针压缩会自动失效)。
- Mark Word:8 字节
- Klass Pointer:未压缩,占用 8 字节
- 实例数据:0 字节
- 当前总和:8 + 8 + 0 = 16 字节
注意:16 已经是 8 的倍数,不需要填充。
结论:还是 16 字节
情况 C:32 位 JVM(古董级环境)
- Mark Word:4 字节
- Klass Pointer:4 字节
- 总计:8 字节
四、 眼见为实:JOL 工具验证
空口无凭,我们使用 OpenJDK 提供的 JOL (Java Object Layout) 工具来打印对象的内存布局。
引入依赖:
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.16</version> </dependency>
测试代码:
import org.openjdk.jol.info.ClassLayout;
public class ObjectSizeTest {
public static void main(String[] args) {
Object obj = new Object();
// 打印对象布局
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
控制台输出(JDK 1.8, 64 位, 默认开启指针压缩):
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
五、 避坑指南:常见误区
误区 1:指针压缩能减少所有对象的大小?
真相:不一定。 就像 new Object(),开启压缩是 8+4+4(填充)=16 字节;关闭压缩是 8+8=16 字节。 对于空对象,指针压缩并没有节省内存空间,只是把“类型指针”占用的空间换成了“填充”空间。但对于包含多个引用字段的复杂对象,指针压缩效果非常显著。
误区 2:数组对象也只占 16 字节?
真相:错误。 数组对象除了对象头,还多了一个 4 字节 的空间来存储 数组长度。 new int[0] 在开启压缩时占用:8(Mark) + 4(Klass) + 4(Length) = 16 字节(正好不需要填充)。
误区 3:所有 CPU 缓存行都是 64 字节?
虽然常见的 x86 架构 CPU 缓存行(Cache Line)通常是 64 字节,这与对象对齐(8 字节)是两个层面的概念。对象对齐是为了让 CPU 无论是读取 32 位还是 64 位数据,都能一次性高效访问,避免跨缓存行读取。
六、 总结与建议
下次面试官问你:“new Object() 占多少内存?”
你可以自信地回答:
“在主流的 64 位 JVM 中,无论是否开启指针压缩,new Object() 都占用 16 字节。
区别在于内部结构:
- 开启压缩:8 字节 Mark Word + 4 字节 Klass Pointer + 4 字节对齐填充。
- 关闭压缩:8 字节 Mark Word + 8 字节 Klass Pointer。”。
架构师建议: 在进行海量对象存储设计(如本地缓存、对象池)时,计算内存容量千万不要只算字段大小,对象头和对齐填充的开销(Overhead)往往比你想象的要大得多!
以上关于new Object() 在 JVM 中到底占多大内存?的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » new Object() 在 JVM 中到底占多大内存?

微信
支付宝