Java并发--对象头

Java对象头

  • 如果对象为非数组类型,用2字宽存储对象头。
  • 如果对象为数组类型,用3字宽存储对象头。

在32位虚拟机中,1字宽 等于4字节,即32bit,如下表所示:
在这里插入图片描述

对象头的组成

Mark Word:

Java对象头里的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。

  • 32位JVM 的Mark Word的默认存储结构如下:
    在这里插入图片描述

    在运行期间,Mark Word里存储的数据会随着锁标志位的变化而变化。Mark Word可能变 化为存储以下4种数据
    在这里插入图片描述

  • 在64位虚拟机下,Mark Word是64bit大小的,其存储结构如下:
    在这里插入图片描述

具体结构如下:(32bit)
在这里插入图片描述

其中各部分的含义如下:

  • 锁标记位(lock):该标记的值不同,整个mark word表示的含义不同
    在这里插入图片描述

  • 是否为偏向锁(biased_lock):对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。

  • 对象分代年龄(age):4位的Java对象年龄。在GC中,如果对象在Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。由于age只有4位,所以最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的原因。

  • identity_hashcode: 25位的对象标识Hash码,采用延迟加载技术。调用方法System.identityHashCode()计算,并会将结果写到该对象头中。当对象被锁定时,该值会移动到管程Monitor中。

  • thread: 持有偏向锁的线程ID。

  • epoch:偏向时间戳。

  • ptr_to_lock_record:指向栈中锁记录的指针。

  • ptr_to_heavyweight_monitor:指向管程Monitor的指针。

(64位):

在这里插入图片描述

class pointer:

这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。

为了节约内存可以使用选项+UseCompressedOops开启指针压缩,其中,oop即ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:

  1. 每个Class的属性指针(即静态变量)
  2. 每个对象的属性指针(即对象变量)
  3. 普通对象数组的每个元素指针

当然,也不是所有的指针都会压缩,一些特殊类型的指针JVM不会优化,比如指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。

array length:

如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,这部分数据的长度也随着JVM架构的不同而不同:32位的JVM上,长度为32位;64位JVM则为64位。64位JVM如果开启+UseCompressedOops选项,该区域长度也将由64位压缩至32位。

发布了798 篇原创文章 · 获赞 2193 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/cold___play/article/details/104494045