在Java面试中,对象内存占用是一个经典问题。当面试官问"new Object()在JVM中占多大内存"时,他们实际上在考察你对JVM内存模型的深入理解。这个问题看似简单,但涉及指针压缩、对象头、内存对齐等多个关键技术点。
我们先明确几个基本概念:
一个Java对象在堆内存中的存储布局可以分为三个部分:
对象头包含两类信息:
在64位JVM中,Mark Word占8字节(不考虑压缩)
指向对象元数据的指针,JVM通过这个指针确定对象是哪个类的实例。
在64位JVM中:
存储对象真正的有效信息,即我们在代码里定义的各种字段内容。对于Object类,这部分为空。
HotSpot VM要求对象起始地址必须是8字节的整数倍,因此当对象大小不是8的倍数时,需要对齐填充。
让我们计算一个最简单的Object对象在64位JVM中的内存占用:
因此:
我们可以使用JOL(Java Object Layout)工具来验证这个结论:
java复制// 添加Maven依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
// 测试代码
public static void main(String[] args) {
System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
}
输出结果示例(开启指针压缩):
code复制java.lang.Object object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80001e5
12 4 (object alignment gap)
Instance size: 16 bytes
对象内存占用会受到以下因素影响:
JVM会对字段进行重排序以优化内存占用:
数组对象会在对象头中多出4字节存储数组长度,因此:
为什么需要内存对齐?
对象头为什么需要存储这么多信息?
如何准确测量大型应用的内存占用?
假设我们有一个User类:
java复制class User {
int id;
String name;
boolean isVip;
}
内存占用分析:
通过JOL验证:
code复制User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 int User.id 0
16 1 boolean User.isVip false
17 3 (alignment/padding gap)
20 4 String User.name null
Instance size: 24 bytes
最后分享一个实用技巧:在性能敏感的场景,可以使用-XX:+PrintFieldLayout参数查看字段排列顺序,帮助优化内存布局。