对象锁升级的过程详解

1、java对象的内存布局

一个java普通对象在内存中分为4部分:

  • Markword

    主要记录对象的锁状态

  • class pointer

    指向对象字节码的指针

  • instance data

    实例数据

  • padding

    jvm设计时对象所占大小要被8整除,要是位数不够需要加padding

image-20200909165625022

2、对象布局的查看

使用JOL类可以查看对象的内存布局,maven引入如下依赖即可:

    <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.9</version>
    </dependency>

以new Object()对象为例,看一下32位和64位上的差异。

32位

在这里插入图片描述

64位

在这里插入图片描述

可以看出在32位机上一个Object对象占8个字节,而在64位机上占16个字节。那为什么两个Markword不一样呢?

在64位jvm上执行java -XX:+PrintCommandLineFlags -version可以看到:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YMelErMs-1649900403442)(C:\Users\10262863\AppData\Roaming\Typora\typora-user-images\image-20211215125727343.png)]

UseCompressedOops:普通对象指针压缩,oops: ordinary object pointer
UseCompressedClassPointers:类指针压缩

这两个参数会影响jvm的内存布局,具体如下:

本身classpointer是跟操作系统位数一样的,因为默认开启了UseCompressedClassPointers,所以而UseCompressedClassPointers则使用32-bit的offset(也就是4个字节)来代表64-bit进程中的class pointer;

也就是64位操作系统由于开启类指针压缩,所以4个字节来表示classpointer。为什么32位机器上也是4位呢?我们使用java -XX:+PrintCommandLineFlags -version在32位机器上看一下:
在这里插入图片描述

可以看出32位机默认上并没有开启指针压缩,因此,classpointer就是32位,4个字节。而不是2个字节。

而**markword大小跟操作系统是对应的,32位操作系统就是4个字节,64位操作系统就是8个字节**。

3、无锁态的markword

看一下64位和32的区别

32位

img

在这里插入图片描述

两张图对应可以看出,new Object是无锁态,锁的标志是001,至于为什么说001不在低位,原因是大小端存储区别。内存里面是小端存储

  • 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。
  • 小端字节序:低位字节在前,高位字节在后,即以0x1122形式储存。

计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。

人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。

由于无锁状态,所以剩下的30位都为0。无锁的时候会记录hashcode,我们使用一下hashcode方法,看一下内存布局有什么变化。
在这里插入图片描述

可以看出最高的30位已经变成了对象的hashcode,01000001 10100010 01010000,我们把它倒过来变成大端写法:01010000 10100010 01000001 00001001

然后使用System.out.println(Integer.toBinaryString(i));

打印一下对象的hashcode,如下10100001 01000100 10000010,正好内存布局的hashcode对上了

64位

image-20200910180214679

(省略,类似上面的32位)

4、锁升级的过程详解

以64位为例

无锁态

new 对象之后markword的锁标志就是001,如果没有调用过hashcode方法,对应的hashcode位就全为0。

偏向锁

markword里面记录了指向当前线程的指针,54位,标志位变成101.

轻量级锁

线程栈生成LR,markword指向线程栈中的LR指针。 当有其他线程竞争的时候,锁标志由偏向锁变成轻量级锁(00),通过自旋的方式完成,也就是CAS操作。

如果太占用cpu资源,就会升级为重量级锁。

重量级锁

如果竞争加剧,或者自旋超过10次,或者占用cpu资源的1/2.申请锁必须要经过操作系统老大kernel进行系统调用,入队进行排序操作,操作完之后再返回给用户态。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值