HotSpot虚拟机对象探秘

HotSpot虚拟机对象探秘

1. 对象的创建

  1. 检查这个质指令的参数是否能在常量池中找到一个类的符号引用,并检查符号引用所代表的类是否被加载,如果没有必须先进行类加载的动作

  2. 类加载检查完成后,便会为对象分配内存,对象所需的内存在类加载完成后便可完全确定。分配方式有俩种,选择方式取决于java堆是否规整,是否规整又与垃圾回收器有关。

    • 指针碰撞
    • 空闲列表
  3. 由于对象创建非常频繁,所以涉及到并发线程安全问题,解决方案有俩种:

    • 保证操作的原子性
    • 先在本地线程缓冲区(TLAB)进行分配,分配不了,再分配心得缓冲区时才需要同步锁定
  4. 分配完成后,将分配到的空间的(不包括对象头)都初始化为0值,如果是使用TLAB的话,这步操作可以在TLAB中进行。这步操作的主要目的是保证了对象的实例字段在不初始化的时候就能直接使用。

  5. 之后还需要对对象头进行一些配置,包括比如类型信息,元数据信息,对象哈希码、GC分代年龄等信息。以及是否使用偏向锁

    通俗的讲,偏向锁就是在运行过程中,对象的锁偏向某个线程。即在开启偏向锁机制的情况下,某个线程获得锁,当该线程下次再想要获得锁时,不需要再获得锁(即忽略synchronized关键词),直接就可以执行同步代码,比较适合竞争较少的情况。

    偏向锁获取流程:

    (1)查看Mark Word中偏向锁的标识以及锁标志位,若是否偏向锁为1且锁标志位为01,则该锁为可偏向状态。

    (2)若为可偏向状态,则测试Mark Word中的线程ID是否与当前线程相同,若相同,则直接执行同步代码,否则进入下一步。

    (3)当前线程通过CAS操作竞争锁,若竞争成功,则将Mark Word中线程ID设置为当前线程ID,然后执行同步代码,若竞争失败,进入下一步。

    (4)当前线程通过CAS竞争锁失败的情况下,说明有竞争。当到达全局安全点时之前获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码。

    偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁状态的线程才会释放锁,线程不会主动去释放偏向锁。偏向锁的撤销需要等待全局安全点(即没有字节码正在执行),它会暂停拥有偏向锁的线程,撤销后偏向锁恢复到未锁定状态或轻量级锁状态。

    轻量级锁不是用来替代传统的重量级锁的,而是在没有多线程竞争的情况下,使用轻量级锁能够减少性能消耗,但是当多个线程同时竞争锁时,轻量级锁会膨胀为重量级锁。

    重量级锁即当有其他线程占用锁时,当前线程会进入阻塞状态。

    自旋锁: 在自旋状态下,当一个线程A尝试进入同步代码块,但是当前的锁已经被线程B占有时,线程A不进入阻塞状态,而是不停的空转,等待线程B释放锁。如果锁的线程能在很短时间内释放资源,那么等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞状态,只需自旋,等持有锁的线程释放后即可立即获取锁,避免了用户线程和内核的切换消耗。

  6. 现在从虚拟机视角 一个对象已经诞生了,但从java程序视角对象的创建才刚刚开始,因为还未执行构造函数。

2. 对象的内存布局

对象在堆中的布局可以分为三个部分:对象头、实例数据、对齐填充

对象头主要包括俩个部分,一是类型指针、二是对象运行时的数据

类型指针指向的是它的类型元数据。

对象运行时的数据被官方成为Mark Wrod , 主要包括哈希码,GC分代年龄,锁状态标志等。

实例数据的存储顺序会受到虚拟机分配策略和在源码中定义顺序的影响。

字节填充没有实际意义,只是为了满足对象的起始地址必须为8字节的整数倍

3. 对象的访问定位

通过栈上的reference数据来操作堆上的具体对象,但该引用如何访问到对象,不同的虚拟机有着不同的实现方式,目前主流的访问方式有俩种,使用句柄和直接指针

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值