Java 对象模型
HotSpot JVM 使用名为 oops (Ordinary Object Pointers) 的数据结构来表示对象。这些 oops 等同于本地 C 指针。 instanceOops 是一种特殊的 oop,表示 Java 中的对象实例。
在 Hotspot VM 中,对象在内存中的存储布局分为 3 块区域:
- 对象头(Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
对象头又包括三部分:MarkWord、元数据指针、数组长度。
- MarkWord:用于存储对象运行时的数据,好比 HashCode、锁状态标志、GC分代年龄等。这部分在 64 位操作系统下占 8 字节,32 位操作系统下占 4 字节。
- 指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪一个类的实例。这部分就涉及到指针压缩的概念,在开启指针压缩(-XX:+UseCompressedClassPointers )的状况下占 4 字节,未开启状况下占 8 字节。
- 数组长度:这部分只有是数组对象才有,若是是非数组对象就没这部分。这部分占 4 字节。
实例数据就不用说了,用于存储对象中的各类类型的字段信息(包括从父类继承来的)。
关于对齐填充,Java 对象的大小默认是按照 8 字节对齐,也就是说 Java 对象的大小必须是 8 字节的倍数。若是算到最后不够 8 字节的话,那么就会进行对齐填充。

基础对象占用存储空间
Java 基础对象在内存中占用的空间如下:
| 类型 | 占用空间(byte) |
|---|---|
| boolean | 1 |
| byte | 1 |
| short | 2 |
| char | 2 |
| int | 4 |
| float | 4 |
| long | 8 |
| double | 8 |
JOL(Java Object Layout)是用于分析 JVM 中对象布局方案的微型工具箱。这些工具大量使用 Unsafe、JVMTI 和 Serviceability Agent (SA) 来解码实际的 对象布局、占用空间和引用。这使得 JOL 比其他依赖堆转储、规范假设等的工具更准确。
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.17</version>
</dependency>
Integer占用多少字节
由于现在基本都是 64 位的虚拟机,所以后面的讨论都是基于 64 位虚拟机。
ClassLayout classLayout = ClassLayout.parseInstance(4);
System.out.println(classLayout.toPrintable());
jvm参数:-XX:+UseCompressedClassPointers
执行结果
java.lang.Integer object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0x00025938
12 4 int Integer.value 4
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
jvm参数:-XX:-UseCompressedClassPointers
java.lang.Integer object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x000001ff6316fd80
16 4 int Integer.value 4
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
一个空对象占用多少字节
publci class EmptyObject {
}
理论上一个空对象占用内存大小只有对象头信息,对象头占 8+4=12 个字节。那么 EmptyObject.class 应该占用的存储空间就是 12 字节,考虑到 8 字节的对齐填充,那么会补上 4 字节填充到 8 的 2倍,总共就是 16字节。怎么验证我们的结论呢?JDK 提供了一个工具,JOL 全称为 Java Object Layout,是分析 JVM 中对象布局的工具,该工具大量使用了 Unsafe、JVMTI 来解码布局情况。下面我们就使用这个工具来获取一个 Java 对象的大小。
public class HowManyBytesObjectOccupy {
@Test
public void testEmptyObject() {
ClassLayout classLayout = ClassLayout.parseInstance(new EmptyObject());
System.out.println(classLayout.toPrintable());
}
}
class EmptyObject {
}
jvm参数:-XX:-UseCompressedClassPointers
javas.advanced.EmptyObject object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x0000025eb9b60598
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
jvm参数:-XX:+UseCompressedClassPointers
javas.advanced.EmptyObject object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0x0101a140
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
测试其它
class FullObject {
private byte b;
private char type;
private short age;
private int no;
private float weight;
private double price;
private long id;
private boolean flag;
private String str;
private LocalDateTime dateTime;
private String[] strs;
private List<String> strList;
}
@Test
public void testFullObject() {
ClassLayout classLayout = ClassLayout.parseInstance(new FullObject());
System.out.println(classLayout.toPrintable());
}
未指定jvm参数-XX:+UseCompressedClassPointers,但默认是开户压缩。
结果是
javas.advanced.FullObject object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0x0101a140
12 4 int FullObject.no 0
16 8 double FullObject.price 0.0
24 8 long FullObject.id 0
32 4 float FullObject.weight 0.0
36 2 char FullObject.type
38 2 short FullObject.age 0
40 1 byte FullObject.b 0
41 1 boolean FullObject.flag false
42 2 (alignment/padding gap)
44 4 java.lang.String FullObject.str null
48 4 java.time.LocalDateTime FullObject.dateTime null
52 4 java.lang.String[] FullObject.strs null
56 4 java.util.List FullObject.strList null
60 4 (object alignment gap)
Instance size: 64 bytes
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
注意有两处padding
- 第一处是OFF(OFFSET)为42,原因是后面的字段是4byte,而此处缺少2byte,不能把后面字段的4byte拆开,所以要添加padding。
- 第二处是OFF(OFFSET)为60。全部实例数据后需要padding。
最后编辑:张三 更新时间:2025-03-28 14:56