Java 对象结构与锁实现原理以及 MarkWord 理解

Java 对象结构与锁实现原理以及 MarkWord 理解

Java 对象结构与锁实现原理以及 MarkWord 详解

Mark Word记录了对象和锁有关的信息,当这个对象被synchronized关键字当成同步锁时,围绕这个锁的一系列操作都和Mark Word有关。

Mark Word在32位JVM中的长度是32bit,在64位JVM中长度是64bit。

状态标志位存储内容
未锁定01对象哈希码、对象分代年龄
轻量级锁定00指向锁记录的指针
重量级锁定10执行重量级锁定的指针
GC 标记11空(不需要记录信息)
可偏向01偏向线程的ID、偏向时间戳、对象分代年龄

markWord示意图

jvm如何使用锁和Mark Word?

  1. 没有被锁时,就是一个普通对象,Mark Word 记录对象的 HashCode,锁标志位是 01 是否偏向位 0;
  2. 当对象被当做同步锁并且有一个线程抢到了锁,锁标志位还是 01,但是否偏向位是1,前面23bit 保存抢到锁的线程id,表示进入偏向状态。
  3. 当线程 A 再次试图获取锁时, JVM 发现同步锁对象的标志位是 01,是否偏向也是1,并且记录中线程id 也是线程 A 自己的 id ,可以直接执行同步代码块。
  4. 当线程 B 试图获取这个锁时,JVM发现同步锁处于偏向状态,但是mark word 中线程 id 记录不是自己,会有一个锁升级(轻量级锁),两个线程公平竞争,先抢到的线程占有锁对象并执行代码,锁对象的 Mark Word 就执行哪个线程的栈帧中的锁记录。(升级轻量级锁时,JVM 会在当前线程的线程栈中开辟一块单独的空间,里面保存对象的Mark Word 的副本,同时在对象锁Mark Word 中保存指向这片空间的指针。)这里的操作都是 CAS ,如果保存成功,则表示抢到了同步锁,把 MarkWord 的标志位改成 00. 可以执行同步代码块。如果执行失败,执行步骤5 。
  5. 轻量级锁抢锁失败,JVM 会使用自旋锁,自旋锁并不是一个锁状态。只是代表不断的重试(自旋的次数由 JVM 控制,依据版本的不同次数也不相同),尝试抢锁。
  6. 自旋锁重试之后依然没有抢到锁,升级为重量级锁。标志位改成 10 。这个状态下,未抢到锁的线程都会被阻塞。

指针压缩

如果应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64位的JVM将会比32位的JVM多耗费50%的内存。为了节约内存可以使用选项 +UseCompressedOops 开启指针压缩,其中,oop即ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:

  1. 每个Class的属性指针(即静态变量)

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

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

# java 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×