Java 对象结构之 markword

在 Java 虚拟机中,对象在内存中的结构可以划分为4部分区域:

  • markword
  • 类型指针(_klass)
  • 实例数据(instance_data)
  • 对齐填充(padding)

我们用 Java Object Layout 工具来看下,首先创建一个 Maven 工程,并依赖 JOL 二方包:
Maven Jol

<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>

在 main 方法中编写代码:

Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());

运行并查看结果:

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
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

在这里插入图片描述

从结果我们可以得知 markword 占用对象大小的 8 字节, 类型指针占用 4 字节,由于 java.lang.Object 中没有属性,因此没有这部分内存占用。而 Java 对象为了实现 8 字节对齐,实际大小都是 8 字节的倍数。为了实现对齐填充,最后占用了额外的 4 字节,使得最终大小为 16 字节。

markword

markword 中包含了和 Java 对象息息相关的一些信息,它的实际大小一般和 CPU 字长保持一致,如在 32 位CPU上 markword的大小一般为 32位,即 4 字节;而在 64 位CPU上 markword 的大小一般为 64 位,即 8 字节。由于我的CPU是 64位的,并且 JVM 也是使用的 64 位的,所以这里可以看到 markword 占用了 8 字节大小。当然,如果你在64位CPU上调用了32位的JDK程序,执行效果和32位CPU上的执行效果是一致的。
在这里插入图片描述
下载链接
在这里插入图片描述

markword 中一般包含三类信息,GC年龄、锁标识和对象 hashCode。

对象在创建后 hashCode 并没有立即更新到对象头当中,当我们调用了 hashCode方法后,hashCode 才会被写入到 hashCode 当中。

Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
obj.hashCode();
// 在调用 hashCode 方法后,可以看到对象头内容发生了变化
System.out.println(ClassLayout.parseInstance(obj).toPrintable());

在这里插入图片描述
hashCode 的计算方式在不同的JVM中具体实现逻辑不一样,当两个对象都是使用默认的hashCode 方法时,JVM可以保证这两个对象生成的hashCode是不同的。根据当前对象的地址进行计算的 ,我们可以自定义Java类并重写hashCode方法。在这种情况下重写的 hashCode 方法并不会同步更新对象头。

markword 中还包含了Java 对象的分代年龄,我们可以通过调用System.gc()手动触发 GC 来查看分代年龄的变化:

Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
System.gc();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());

在这里插入图片描述


除此之外,我们还可以通过使用 synchronized关键字来查看对象头的变化:

Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj) {
    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}

在这里插入图片描述

我们还可以用这个工具查看一下类的信息:

System.out.println(ClassLayout.parseClass(String.class).toPrintable());

在这里插入图片描述
由于类对象是由类加载器加载的C++对象,所以这里无法获取到对应的markword和 class 指针等信息.

参考资料

JOL (Java Object Layout)
Java Object Layout (JOL)
Java对象结构详解
Java对象在内存的结构
浅谈Java中的hashcode方法

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值