1.2HotSpot虚拟机对象

1.2HotSpot虚拟机对象

1.对象的创建

类的初始化->类的实例化

  1. 过程:类的初始化和实例化过程
    1. 类的初始化:调用方法【只调用1次】
    2. 类的实例化(即对象的实例化):类的初始化结束后,JVM开始为新生对象分配内存,分配完后初始化内存空间为零值。然后就调用方法为对象进行初始化

2.对象的内存布局

对象=对象头+实例数据+对齐填充(可能会有)

(1)对象头

①markword:
  1. 图解:32位markword[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bzNXrbsC-1686273872334)(C:\Users\10059\AppData\Roaming\Typora\typora-user-images\image-20220304101423558.png)]

  2. JVM一般是这样使用markword中的锁状态

    • 偏向锁,轻量锁,重量锁

    偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。
    一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个
    线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操作,并将
    对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。
    一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。
    轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。 但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。

    • 锁膨胀(升级)过程:以Synchronized的锁升级为例
    1,当没有被当成锁时,这就是一个普通的对象,Mark Word记录对象的HashCode,锁标志位是01,是否偏向锁那一位是0。
    
    2,当对象开始有线程A来访问它时,锁标志位还是01,但是否偏向锁那一位改成1,前23bit记录抢到线程A的id,表示对象进入偏向锁状态。
    
    3,此时当线程B试图获得这个对象时,JVM发现该对象锁处于偏向状态,但是Mark Word中的线程id记录的不是B,那么线程B会先用CAS操作试图获得锁,这里的获得锁操作是有可能成功的,因为线程A一般不会自动释放偏向锁。如果线程A执行完同步代码块释放锁,则线程B抢锁成功,就把Mark Word里的线程id改为线程B的id,代表线程B获得了这个偏向锁,可以执行同步锁代码。如果抢锁失败,则继续执行步骤4。
    
    4,偏向锁状态抢锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。JVM会在原持有偏向锁的线程A栈中开辟一块单独的空间,里面保存对象锁Mark Word,同时在对象锁Mark Word中保存指向这片空间的指针。其余线程争抢锁的线程也同样会开辟一块空间保存对象锁Mark Word,然后开始自旋抢锁,谁抢到锁,对象头mark word轻量锁指针就指到哪个线程的栈中锁记录空间。
    
    5,轻量级锁抢锁失败,JVM会使用自旋锁,自旋锁不是一个锁状态,只是代表不断的重试,尝试抢锁。从JDK1.7开始,自旋锁默认启用,自旋次数由JVM决定。如果抢锁成功则执行同步锁代码,如果失败则继续执行步骤6。
    
    6,自旋锁达到一定次数后如果抢锁依然失败,轻量级锁会升级至重量级锁,锁标志位改为10。对象头mark word会保存指到ObjectMonitor(对象监视器)的指针。在这个状态下,未抢到锁的线程都会被阻塞。
    
    • 锁膨胀详细图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYi9juWR-1686273872336)(C:\Users\10059\Desktop\2bcc8161c52eb100d2c7c4c96c70d3c5823.webp)]

②kclass:指向方法区中类型信息
③数组长度:如果是数组对象的话对象头会多出一个数组长度信息

(2)实例数据

实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。

(3)对齐填充(可能会有)

对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全

3.对象的访问定位

通过“直接指针”方式去访问和定位

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

通过“直接指针”方式去访问和定位

[外链图片转存中…(img-rQbdfbFb-1686273872337)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值