标签:art 自身 add 信息 官方 指针 一个 替换 空间
在 HotSpot 虚拟机中,对象在内存中存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
HotSpot
虚拟机对象的对象头一般包含两部分信息,第一部分用于存储对象自身的运行时数据,例如HashCode
、GC
分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等信息。官方称这部分数据为Mark Word
。在32
位和64
位的JVM
中,这部分数据分别为32bit
和64bit。
另一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM
通过这个指针确定对象是哪个类的实例。在32
位JVM
中,指针的长度为32bit
,在未开启压缩指针的64
位JVM
中,该指针的长度为64bit
,如果开启压缩指针,那么为32bit
。
之前提到对象头一般包含两部分信息,这是因为如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,并且这部分数据也随着JVM
位数的不同而不同:32
位的JVM
上,该区域的长度为32bit
,在64
位未开启压缩指针的JVM
中,这部分数据的长度为64bit
,否则为32bit
。
加锁过程
在代码进入同步块的时候,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word),这时候线程堆栈与对象头的状态如下图所示。
然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后两个Bits)将转变为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如下图所示。
如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。
解锁过程
解锁过程也是通过CAS操作来进行的,如果对象的Mark Word仍然指向着线程的锁记录,那就用CAS操作把对象当前的Mark Word和线程中复制的Displaced Mark Word替换回来,如果替换成功,整个同步过程就完成了。如果替换失败,说明有其他线程尝试过获取该锁,那就要在释放锁的同时,唤醒被挂起的线程。
参考:JVM中锁优化简介
标签:art 自身 add 信息 官方 指针 一个 替换 空间
原文地址:https://www.cnblogs.com/rouqinglangzi/p/10260256.html