java对象的内存布局

你是否想过这些问题

  • 对象中的锁状态是如何标记的?
  • 一个Object对象在内存中占用多大?

对象在内存中存储的布局

对象在内存中存储的布局.png

  • 对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象才有)等。
  • 实例数据:存放类的属性数据信息,包括父类的属性信息;
  • 对齐填充:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐。

深入理解对象头

  • Mark Word:用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”。
  • Klass Pointer:对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。 32位4字节,64位开启指针压缩或最大堆内存<32g时4字节,否则8字节。jdk1.8默认开启指针压缩后为4字节,当在JVM参数中关闭指针压缩(-XX:-UseCompressedOops)后,长度为8字节。
  • 数组长度(只有数组对象有):如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度。 4字节

对象头.png

查看内存布局的方式:JOL

  • 需要引入的jar包
<!-- 查看Java 对象布局、大小工具 -->
<dependency>
	<groupId>org.openjdk.jol</groupId>
	<artifactId>jol-core</artifactId>
	<version>0.10</version>
</dependency>

  • 在java中使用的方式
// 定义对象
Object obj = new Object();
// 查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
  • 执行的结果

Object对象的内存布局.png

一个obj对象占多少个字节?

  • Instance size: 16 bytes
  • Mark Word占用8个字节
  • Klass Pointer占用4个字节(压缩后)
  • 虚拟机要求的对齐填充位(8的倍数):需要补充4个字节的对齐填充位

Mark Word的结构

  • hash: 保存对象的哈希码。运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。
  • age: 保存对象的分代年龄。表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
  • biased_lock: 偏向锁标识位。由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。
  • lock: 锁状态标识位。区分锁状态,比如11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。
  • JavaThread*: 保存持有偏向锁的线程ID。偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念。
  • epoch: 保存偏向时间戳。偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。

32位JVM下的对象结构描述

32位JVM下的对象结构描述.png

64位JVM下的对象结构描述

64位JVM下的对象结构描述
.png

  • ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。当锁获取是无竞争时,JVM使用原子操作而不是OS互斥,这种技术称为轻量级锁定。在轻量级锁定的情况下,JVM通过CAS操作在对象的Mark Word中设置指向锁记录的指针。
  • ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针。如果两个不同的线程同时在同一个对象上竞争,则必须将轻量级锁定升级到Monitor以管理等待的线程。在重量级锁定的情况下,JVM在对象的ptr_to_heavyweight_monitor设置指向Monitor的指针

锁状态枚举的对应

  • locked_value = 0, //00 轻量级锁
  • unlocked_value = 1, //001 无锁
  • monitor_value = 2, //10 监视器锁,也叫膨胀锁,也叫重量级锁
  • marked_value = 3, //11 GC标记
  • biased_lock_pattern = 5 //101 偏向锁

结束语

  • 获取更多有价值的文章,让我们一起成为架构师!
  • 关注公众号,可以让你对MySQL有非常深入的了解
  • 关注公众号,每天持续高效的了解并发编程!
  • 这个公众号,无广告!!!每日更新!!!
    作者公众号.jpg
posted @ 2022-01-17 01:13  程序java圈  阅读(55)  评论(0编辑  收藏  举报