【对象头】JVM 中的对象结构

发布时间 2023-03-24 07:14:36作者: 酷酷-

1  前言

Java 本身是面向 OOP 编程的,我们代码中创建的对象经过编译装载进我们的 JVM 中,那么我们的实例对象在 JVM 中具体表现的结构是什么样的呢,就是我们这节要看的东西。

2  工具

在了解之前我们要看到实际的东西,就是我们可能知道有对象头、实例数据、对齐,但是这毕竟是概念,我们怎么看到具体真实的数据呢,把下边这个 jar包引入自己的工程:

https://repo.maven.apache.org/maven2/org/openjdk/jol/jol-cli/0.9/,找到 jol-cli-0.9-full.jar,然后引入到自己的工程中。

涉及的 JVM 参数:

  • -XX:+UseCompressedOops:开启压缩指针,如果JVM的版本在 Java SE 6 update 23 及以上, 则不需要再设置 -XX:+UseCompressedOops 参数, 因为默认会开启。
  • -XX:-UseCompressedOops:关闭压缩指针 
  • 压缩指针:顾名思义可能节省内存开销吧

示例代码:

public static void main(String[] args) {
    Person person = new Person("狗子", 1, Boolean.TRUE);
    //打印虚拟机的信息
    System.out.println(VM.current().details());
    //打印对象大小
    System.out.println(ClassLayout.parseInstance(person).instanceSize());
    //打印对象头大小
    System.out.println(ClassLayout.parseInstance(person).headerSize());
    //打印对象信息
    System.out.println(ClassLayout.parseInstance(person).toPrintable());
}

3  对象在内存的结构

那么我们有了工具,其实大概能看出来一个对象在内存中的组成:

由3部分组成:

  • 对象头:对象头又可以划分三部分:Mark Word、Class Pointer、数组长度
  • 实例数据:从上边我们的例子中可以看到就是我们成员变量占用的字节数,小细节:static 修饰的不会存在这里
  • 对齐字节:对齐倍数的补充字节

这里我们主要看下对象头:

  • Mark Word: 存储对象自身的运行数据;
  • Class Pointer: 类指针也就是当前对象所引用的类的地址即是哪个类的对象,因为我们的Class文件装载进JVM中放到方法区, 会是一个C++对象也叫KClass对象,所以这里也叫Klass Word;
  • 数组长度:当对象是数组的时候使用;

我们平时使用的 Synchronized java内置锁,锁对象可以是任意对象,锁的信息其实就是存放到了 Mark Word 中,在 JDK 1.6 之前,内置锁都是重量级锁,效率低下。在 JDK 1.6 之后为了提高 synchronized 的效率,才引入了偏向锁轻量级锁

针对 Mark Word,如果JVM是32位,则Mark Word是32bit;如果64位,则Mark Word是64bit。我们这里以64位的详细来看下:

4  小结

这节我们简单看了下我们的对象在 JVM 中的结构组成,主要的就是对象头中的东西,涉及到了我们平时用到的锁,我们下节针对这几种锁展开细致的讲解,有理解不对的地方欢迎指正哈。