详解 Java 对象在 HotSpot JVM 中的内存布局

小鹿同学
小鹿同学
发布时间:2026-10-15 | 5人浏览过
原创

本文详细拆解了HotSpot虚拟机中Java对象的内存布局结构,涵盖对象头、实例数据及对齐填充三大部分,并通过使用JOL工具演示了具体的分析方法,为理解JVM内存模型和优化Java应用性能提供实践参考。

对象内存结构的组成部分

在HotSpot虚拟机中,创建一个对象时,其在内存中的存储布局主要分为三个区域:对象头(Header)、实例数据(Instance Data)以及对齐填充(Padding)。理解这三部分有助于掌握对象在堆中的实际占用大小。

第一部分:对象头(Object Header)

对象头是Java对象存储的核心区域,它包含了两个关键部分的信息:

  1. Mark Word:用于存储对象自身的运行时数据,这是对象头中最“花哨”的部分。其内容随着对象的状态变化而变化,包括哈希码(HashCode)、GC分代年龄、同步锁信息以及偏向锁标识等。在64位JVM环境下,Mark Word默认长度为64bit(8字节),若开启指针压缩则为32bit(4字节)。Mark Word的具体结构在不同状态下有所差异:

2.类型指针(Klass Pointer):这是一个指向方法区中该对象所属类元数据的指针。通过这个指针,JVM能够确定该对象具体属于哪个类的实例。同样在开启指针压缩后,通常占用32bit或64bit空间。

注意:如果对象是一个数组类型,对象头还需要包含额外的空间来存储数组的长度。因为JVM无法仅从类的元数据判断数组的大小,必须依赖这块记录。

第二部分:实例数据(Instance Data)

这部分是对象真正存储的有效信息,即类定义的各种类型字段内容,包括父类中定义的属性。它是对象内存占用最大的部分。在存储顺序上,JVM会优先放置宽度较大的数据类型(如long/double)以满足对齐要求,然后是较窄的类型,最后处理父类字段。

第三部分:对齐填充(Padding)

并不是所有的对象都会存在对齐填充。HotSpot虚拟机要求对象的起始地址必须是8字节的整数倍,因此当对象头与实例数据的总长度不足8的倍数时,会通过补空字节的方式来达到对齐目的。根据计算机组成原理,8字节边界对齐能提升CPU读取内存的效率。

实战分析:使用JOL查看对象内存

为了更直观地观察上述理论,我们可以使用JOL (Java Object Layout) 这一官方提供的工具来分析JVM中对象在内存中的确切布局。

第1步:引入Maven依赖

在现有的Maven项目中添加jool-core依赖:

<dependency>
  <groupId></groupId>org.openjdk.jol</groupId>
  <artifactId></artifactId>jool-core</artifactId>
  <version></version>0.9</version>
</dependency>

第2步:编写测试代码

编写一个简单的Demo类,实例化一个基础Object并使用ClassLayout进行分析:

public class JOLDemo {
    public static void main(String[] args) {
        Object obj = new Object();
        System.out.println("十进制hashCode = " + obj.hashCode());
        
        String str = ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(str);
    }
}

第3步:解读输出结果

运行上述代码,控制台输出如下:

十进制hashCode = 1956725890
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION               VALUE
    0    4       (object header)                           01 a1 44 e5 (00000001 10100001 01000100 11100101) (-134217243)
    4    4       (object header)                           74 00 00 00 (01110100 00000000 00000000 00000000) (116)
    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

结果解析如下:

  • OFFSET:该字段相对于对象起始位置的偏移量。
  • SIZE:占据的字节数。
  • VALUE:对应的二进制/十六进制值,对应Mark Word和Klass Pointer的内容。
  • Instance size:对象总共占用的内存大小为 16 字节。

对于 new Object(),由于其实例数据为空,其对象头(开启指针压缩情况下)通常占用 4+4=8 字节(取决于具体的锁状态和系统版本,这里输出显示为前8字节为对象头)。剩下的 4 字节即为“对齐填充”,使得总大小达到16字节(8的整数倍)。

总结

理解Java对象的内存布局对于排查内存溢出(OOM)问题和调整JVM参数至关重要。通过对齐填充机制的认识,也能更好地解释为什么某些看似很小的Java对象在堆中却占据了几十字节的空间。借助JOL工具,开发者可以清晰地看到每一块内存的去向。

以上就是Java对象的内存布局详细介绍的详细内容,更多关于Java对象内存布局的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表