Java对象的存储布局以及锁状态锁升级过程

 

Java对象在内存中的结构(非数组)
对象头markword(32位JVM占32位,64位JVM占64位)
class pointer(32位JVM占32位,64位JVM在未开起压缩指针时占64位,开启时占32位):object.Class(如String.Class)
如果是数组,这里存数组长度(数组长度占32位),如果不是,则没有这部分
instance data对象属性(以实际对象内属性为准)
paddingjava内存地址按照8bytes对齐,长度必须是8的倍数

 

markword 以及锁升级过程(32位JVM)
锁状态25bit4bit1bit2bit
23bit2bit是否偏向锁锁标志位
无锁状态对象的hashCode分代年龄001
偏向锁线程idEpoch分代年龄101
轻量级锁指向栈中锁记录的指针00
重量级锁指向重量级锁的指针10
GC标记11

无锁状态:前25位存的是对象的hashcode--identity hashCode,26--29 位存的是分代年龄(最大分分代年龄2^4 -1 =15),第30位存储偏向锁标志,第31-32位存储的是锁标志位; 

1、一个对象刚刚new出来的时候处于无锁状态,锁标志位为:01 ,偏向锁标志为: 0 ,|| identity hashCode || GC age || 0 || 01 ||;

2、当第一个线程锁定该对象时,会检查 锁标志位 是否是01 ,然后检查 偏向锁标志位是否为 0,CAS设置线程ID和偏向锁标志位,会进入偏向锁状态:|| 线程ID || Epoch || GC age || 1 || 01 ||  ,偏向锁不是并发,线程重复加锁,由于是偏向于这个线程的,markword记录线程ID和当前线程ID一样,所以直接获得偏向锁;

3、偏向锁被争用的时候回升级为轻量级锁,当第二个线程试图锁定该对象时,会发生争抢,锁状态升级为轻量级锁,轻量级锁实现原理:当线程争用这个锁的时候,会在线程的栈里面建立一个锁记录-LockRecord ,原来的markword (包括hashCode)数据全部复制到了这个LockRecord中,原来的 || 线程ID || Epoch || GC age ||  会被替换成指针,指向这个LockRecord ,然后得到这把偏向锁,过程:

|| 线程ID || Epoch || GC age || 1 || 01 || --> stack上建立LockRecord --> copy markword 到 LockRecord --> CAS 替换 markword 的lockRecod指针 --> || LockRecord Pointer || 01 ||;

4、轻量级锁升级为重量级锁:发生自旋超过10次,或者等待线程超过CPU核数的一半;

Object o = new Object();

其中的o 占4个字节,new Object()在:

32位JVM占8字节:markword:32位,classpointer:32位,如果没有实例数据instance,不需要对齐padding ,最小占用8Byte存储空间;

64位JVM,markword占64位 ,class pointer在不开启压缩存储情况下占64位(开启占32位),没有其他实例属性时,不需要要对齐,占16字节,开启压缩指针占12字节,对齐4个字节,所以也是16字节;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值