对象内存布局
在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头
对象头里面有两部分内容:对象标记Mark Word和类元信息(类型指针)
对象标记Mark Word存储是什么数据?
- 对象哈希码、对象分代年龄
- GC标记
- GC次数
- 同步锁标记
- 偏向锁持有者
类元信息存储的是指向该对象类元数据的首地址
对象头有多大?
在64位系统中,MarkWord占了8个字节,类型指针占了8个字节,一共是16字节
案例说明:
也就是说一个简单的object对象的话,一共是16字节大小
对象头很重要,后面讲到锁升级和降级的时候,就是锁的标志位,在对象头里演变
实例数据
存放类的属性数据信息,包括父类的属性信息
对齐填充
虚拟机要求对象起始地址必须是8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按8字节补充对齐。
锁在内存布局中的标志位
锁升级
锁升级背景:
用锁能够实现数据的安全性,但是会带来性能下降,无锁能够基于线程并行提升程序性能,但是会带来安全性下降,那么怎么平衡呢?
基于Java对象内存布局得知,对象头中的Mark Word根据锁标志位的不同可以完成我们的锁升级策略
锁升级过程:无锁->偏向锁->轻量锁->重量级锁
偏向锁:MarkWord存储的是指向偏向的线程ID
轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针
重量级锁:MarkWord存储的是指向堆中的monitor对象的指针
Java5之前是直接使用Synchronized重量级锁,计算机底层的用户态和内核态之间切换的原理,假如锁的竞争比较激烈的话,性能变低,所以java6之后,为了减少获得锁和释放锁带来的性能消耗,引入了轻量级锁和偏向锁
接下来根据锁的种类和锁演化顺序,给大家来讲解
无锁
初始状态,一个对象被实例化后,如果还没有被任何线程竞争锁,那么它就为无锁状态(001)
偏向锁
在实