一、对象在内存中的存储布局
对象的内存布局分为两种,普通对象和数组对象


1、对象头-Mark Word
用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持久的锁、偏向线程的ID等
通过存储的内容得知对象头是锁机制和GC的重要基础。

以 32位虚拟机为例,来看一下其 Mark Word 的字节具体是如何分配的?
无锁 :
对象的hashcode:25bit ; 存放对象分代年龄:4bit; 存放是否偏向锁的标识位:1bit; 存放锁标识位为01:2bit
偏向锁:
在偏向锁中划分更细。
开辟 25bit 的空间,其中存放线程ID:23bit; 存放Epoch:2bit;存放对象分代年龄:4bit ;存放是否偏向锁标识,:1bit (0表示无锁,1表示偏向锁);锁的标识位还是01
轻量级锁:
在轻量级锁中直接开辟 30bit 的空间存放指向栈中锁记录的指针,2bit 存放锁的标志位,其标志位为00
重量级锁:
在重量级锁中和轻量级锁一样,30bit 的空间用来存放指向重量级锁的指针,2bit 存放锁的标识位,为11
GC标记:
开辟30bit 的内存空间却没有占用,2bit 空间存放锁标志位为11。
其中无锁和偏向锁的锁标志位都是01,只是在前面的1bit区分了这是无锁状态还是偏向锁状态
2、类型指针-Class Pointer
Class Pointer是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
3、对象:实例数据;数组:数组长度+数组数据
如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据。
数组长度:存储数组长度,固定占用4个字节
实例数据、数组数据:存储数据
不同的类型所占的空间不同:

4、对齐填充字节- padding :
用于补齐对象内存长度的。
因为JVM要求java代码的对象必须是8bit的倍数。如果一个对象用不到8N个字节则需要对其填充,以此来补齐对象头和实例数据占用内存之后剩余的空间大小。如果对象头和实例数据已经占满了JVM所分配的内存空间,那么就不用再进行对齐填充了。所有的对象分配的字节总SIZE需要是8的倍数,如果前面的对象头和实例数据占用的总SIZE不满足要求,则通过对齐数据来填满。
二、工具
1、jol工具
Idea 导入 pom依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
jol常用方法:
1.使用jol计算对象的大小(单位为字节):ClassLayout.parseInstance(obj).instanceSize()
2.使用jol查看对象内部的内存布局:ClassLayout.parseInstance(obj).toPrintable()
3.查看对象占用空间总大小:GraphLayout.parseInstance(obj).totalSize()
2、进制工具
三、实验
1、对象 和 数组
(1)对象类型
代码:
public class markword01_EmptyProperties {
public static void main(String[] args) {
System.out.println("空属性-对象布局================================");
markword01_EmptyProperties entity = new markword01_EmptyProperties();
// 打印java 对象内存布局
System.out.println(ClassLayout.parseInstance(entity).toPrintable());
}
}
输出结果:
com.tsj.threads.markword01_EmptyProperties object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c105
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
- OFF(OFFSET):偏移地址,单位字节;
- SZ(SIZE):占用的内存大小,单位为字节;
- TYPE DESCRIPTION:类型描述。
object header为对象头,object header 包含 mark + class;
gap字段,表示补齐padding。
- VALUE:对应内存中当前存储的值;
- Instance size:实例字节数值大小,
即:一个空的java对象(不包含任意字段属性)实例,其实例大小为16Byte。
怎么计算?mark + class + gap = 16.
- Space losses: 0 bytes internal + 4 bytes external
= 4 bytes total:表示内存补齐Padding,占用4个字节
(2)数组
代码:
public class markword01_EmptyArrayEntity {
public static void main(String[] args) {
System.out.println("数组布局================================");
markword01_EmptyArrayEntity[] entity = new markword01_EmptyArrayEntity[4];
// 打印java 对象内存布局
System.out.println(ClassLayout.parseInstance(entity).toPrintable());
}
}
输出结果:
[Lcom.tsj.threads.markword01_EmptyArrayEntity; object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 (array length) 4
12 4 (alignment/padding gap)
16 16 com.tsj.threads.markword01_EmptyArrayEntity markword01_EmptyArrayEntity;.<elements> N/A
Instance size: 32 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
结果分析:
- OFF:偏移地址,单位字节;
- SZ:占用的内存大小,单位为字节;
- TYPE DESCRIPTION:类型描述。
bject header为对象头,object header 包含 mark + class;
gap字段,表示补齐padding。
array length:表示数组长度
- VALUE:对应内存中当前存储的值;
- Instance size:实例字节数值大小,
即:一个空的java数组,其实例大小为32Byte。
怎么计算?mark + class + array length + gap = 32.
- Space losses: 0 bytes internal + 4 bytes external
= 4 bytes total:表示内存补齐Padding,占用4个字节
2、padding对齐 vs 压缩验证
(1) 创建三个不同属性的类
Student:
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
StudentV1:
public class StudentV1 {
private String nameV1;
private Integer ageV1;
private int sexV1;
public String getNameV1() {
return nameV1;
}
public void setNameV1(String nameV1) {
this.nameV1 = nameV1;
}
public Integer getAgeV1() {
return ageV1;
}
public void setAgeV1(Integer ageV1) {
this.ageV1 = ageV1;
}
public int getSexV1() {
return sexV1;
}
public void setSexV1(int sexV1) {
this.sexV1 = sexV1;
}
StudentV2:
public class StudentV2 {
private String nameV1;
private Integer ageV1;
private int sexV1;
private boolean live;
public String getNameV1() {
return nameV1;
}
public void setNameV1(String nameV1) {
this.nameV1 = nameV1;
}
public Integer getAgeV1() {
return ageV1;
}
public void setAgeV1(Integer ageV1) {
this.ageV1 = ageV1;
}
public int getSexV1() {
return sexV1;
}
public void setSexV1(int sexV1) {
this.sexV1 = sexV1;
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
(2) ClassLayout执行输出内存布局:
public static void main(String[] args) {
System.out.println("有属性-对象布局 1================================");
Student student = new Student();
System.out.println(ClassLayout.parseInstance(student).toPrintable());
System.out.println("有属性-对象布局 2================================");
StudentV1 studentV1 = new StudentV1();
System.out.println(ClassLayout.parseInstance(studentV1).toPrintable());
System.out.println("有属性-对象布局 3================================");
StudentV2 studentV2 = new StudentV2();
System.out.println(ClassLayout.parseInstance(studentV2).toPrintable());
}
(3) 输出结果:
有属性-对象布局 1================================
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
有属性-对象布局 2================================
com.tsj.threads.StudentV1 object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800f359
12 4 int StudentV1.sexV1 0
16 4 java.lang.String StudentV1.nameV1 null
20 4 java.lang.Integer StudentV1.ageV1 null
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
有属性-对象布局 3================================
com.tsj.threads.StudentV2 object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800f39e
12 4 int StudentV2.sexV1 0
16 1 boolean StudentV2.live false
17 3 (alignment/padding gap)
20 4 java.lang.String StudentV2.nameV1 null
24 4 java.lang.Integer StudentV2.ageV1 null
28 4 (object alignment gap)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
(4) 结果分析:
- Student:
Instance size: 24 bytes;
24 bytes = mark(8) + class(4) + name(4,压缩) + age(4,压缩) + gap(4)
name 类型:String,age类型:Integer,都属于引用类型。JDK默认开启了压缩,8位压缩至4位。
进行了一次补齐,补齐4bytes
- StudentV1:
Instance size: 24 bytes
24 bytes = mark(8) + class(4) + sexV1(4) + nameV1(4,压缩) + ageV1(4,压缩)
nameV1 类型:String,ageV1类型:Integer,都属于引用类型。JDK默认开启了压缩,8位压缩至4位。另外,sexV1类型为int,基本类型无法压缩。
没有进行补齐
- StudentV2:
Instance size: 32 bytes
24 bytes = mark(8) + class(4) + sexV1(4) + live (1) + gap(3) + nameV1(4,压缩) + ageV1(4,压缩) + gap(4)
进行了两次补齐,一次为internal,为live补齐了3bities,一次为external,为整个对象补齐4字节。
3、锁对象的内存布局
主要是针对synchronized,JDK 1.6 优化了synchronized,提出了锁升级的机制,即无锁-偏向锁-轻量级锁-重量级锁,我这里不验证锁升级的过程,主要验证的数这四种锁在对象头是怎么存储和标识的。
锁类型(按锁的状态分类)
non-biasable 无锁且不可偏向
biasable 无锁可偏向
biased 偏向锁
thin lock 轻量级锁
fat lock 重量级锁
|--------------------------------------------------------------------------------------------------------------|
| Object Header (128 bits) |
|--------------------------------------------------------------------------------------------------------------|
| Mark Word (64 bits) | Klass Word (64 bits) |
|--------------------------------------------------------------------------------------------------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | 无锁
|----------------------------------------------------------------------|--------|------------------------------|
| thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | 偏向锁
|----------------------------------------------------------------------|--------|------------------------------|
| ptr_to_lock_record:62 | lock:2 | OOP to metadata object | 轻量锁
|----------------------------------------------------------------------|--------|------------------------------|
| ptr_to_heavyweight_monitor:62 | lock:2 | OOP to metadata object | 重量锁
|----------------------------------------------------------------------|--------|------------------------------|
| | lock:2 | OOP to metadata object | GC
|--------------------------------------------------------------------------------------------------------------|
————————————————
ock: 锁状态标记位,该标记的值不同,整个mark word表示的含义不同。
biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。
从分布可以得出,看锁标记,直接看后 3 位即可,如果给到你锁类型标识,你只需要看前后2位就行。
biased_lock | lock | 16进制 | 状态 |
---|---|---|---|
0 | 01 | 1 | 无锁 |
1 | 01 | 5 | 偏向 |
0 | 00 | 0 | 轻量 |
0 | 10 | 2 | 重量 |
0 | 11 | 3 | GC |
(1)无锁
代码:
public class SyncTest01 {
public static void main(String[] args) throws InterruptedException {
Student a = new Student();
String str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//01 无锁状态
new Thread() {
public void run() {
//把a作为锁对象
synchronized (a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);
}
}
输出结果:
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
主要锁的状态体现在第一行 object header: mark 的 value部分。
mark标识:0x0000000000000001 (non-biasable; age: 0)
non-biasable; age: 0
(1)non-biasable:表示无锁且不可偏向
(2)age:年龄:0
0x0000000000000001
对象头:0x0000000000000001,二进制表示:1
(2)轻量级锁
代码:
public class SyncTest02 {
public static void main(String[] args) throws InterruptedException {
Student a = new Student();
String str = ClassLayout.parseInstance(a).toPrintable();
System.out.println("未上锁,输出ClassLayout");
System.out.println(str);//01 无锁状态
new Thread(){
public void run() {
//把a作为锁对象
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);
System.out.println("上锁,输出ClassLayout");
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//00 轻量级锁
}
}
输出结果:
未上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000700004f9e9b0 (thin lock: 0x0000700004f9e9b0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
上锁前:
mark标识:0x0000000000000001 (non-biasable; age: 0)
(1)non-biasable; age: 0
non-biasable:表示无锁且不可偏向
(2)0x0000000000000001,
对象头:0x0000000000000001,二进制表示为:1。
上锁后:
mark标识:0x0000700004f9e9b0 (thin lock: 0x0000700004f9e9b0)
(1)thin lock: 0x0000700004f9e9b0
thin lock:表示轻量级锁;
上锁的对象头:0x0000700004f9e9b0,二进制表示为:11100000000000000000100111110011110100110110000,看后两位表示:00,00:表示轻量级锁
(2)0x0000700004f9e9b0
对象头是0x0000700004f9e9b0,二进制表示为:11100000000000000000100111110011110100110110000
加锁前对象处于无锁状态,加锁中处于轻量锁状态
3)偏向锁
同为轻量级锁代码(例子2的),另外还需要设置JVM参数。
JDK默认开启偏向锁,但延时的,需要通过参数-XX:BiasedLockingStartupDelay=0禁用延时。(idea在VM Options设置就行了)
偏向锁的开启和禁止延迟参数:
-XX:BiasedLockingStartupDelay=0 -client -Xmx1024m -Xms1024m
偏向锁的关闭参数
-XX:+UseBiasedLocking -client -Xmx512m -Xms512m
是否要在JVM中启用偏向锁,取决于业务方面
如果加synchronized的方法在大部分时间内都只有一个线程来访问,其他很少的时间才会有多线程来并发访问,那么就有必要开启偏向锁。

输出结果:
未上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007f9c7e0d3005 (biased: 0x0000001fe71f834c; epoch: 0; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
上锁前:
mark标识:0x0000000000000005 (biasable; age: 0)
(1)non-biasable; age: 0
non-biasable:表示无锁且不可偏向
age:年龄:0
(2)0x0000000000000005
对象头是0x0000000000000005,二进制表示为:101。
上锁后:
mark标识:0x00007f9c7e0d3005 (biased: 0x0000001fe71f834c; epoch: 0; age: 0)
(1)biased: 0x0000001fe71f834c; epoch: 0; age: 0
biased:表示偏向锁
上锁的对象:0x0000001fe71f834c,二进制表示为:1111111100111000111111000001101001100,看后三位表示:100,1:表示偏向锁,00:表示轻量级锁
age:年龄:0
如果开启了偏向锁,thread、epoch、age 都为 0
(2)0x00007f9c7e0d3005
对象头是:0x00007f9c7e0d3005,二进制表示为11111111001110001111110000011010011000000000101。
加锁前对象处于无锁状态,加锁中处于偏向锁状态,在偏向锁中,对象头和加锁的对象头不是同一个。
(4)重量锁(无锁 =》轻量级=》重量锁)
代码:
public class SyncTest03 {
public static void main(String[] args) throws InterruptedException {
Student a = new Student();
String str = ClassLayout.parseInstance(a).toPrintable();
System.out.println("未上锁,输出ClassLayout");
System.out.println(str);//01 无锁状态
new Thread() {
public void run() {
synchronized (a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println("第一次上锁,输出ClassLayout");
System.out.println(str);//00 轻量级锁
new Thread() {
public void run() {
synchronized (a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println("第二次上锁,输出ClassLayout");
System.out.println(str);//10 重量级锁
}
}
输出结果:
未上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
第一次上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000700008ebc9b0 (thin lock: 0x0000700008ebc9b0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
第二次上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007f7bd001f13a (fat lock: 0x00007f7bd001f13a)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
未上锁:
mark标识:0x0000000000000001 (non-biasable; age: 0)
(1)non-biasable; age: 0
non-biasable:无锁
第一次加锁,是真正加上锁
mark标识:0x0000700008ebc9b0 (thin lock: 0x0000700008ebc9b0)
(1)thin lock: 0x0000700008ebc9b0
thin lock :轻量级锁
0x0000700008ebc9b0,表示上锁的对象头,二进制为:11100000000000000001000111010111100100110110000,看后两位表示:00,00:表示轻量级锁
(2)0x0000700008ebc9b0
对象头是:0x0000700008ebc9b0
第二次还是对同一把锁方法,存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。
mark标识为:0x00007f7bd001f13a (fat lock: 0x00007f7bd001f13a)
(1)fat lock: 0x00007f7bd001f13a
fat lock :表示重量级锁
0x00007f7bd001f13a,上锁的对象头,二进制为:11111110111101111010000000000011111000100111010,看后两位表示:01,01:表示轻量级锁
(2)0x00007f7bd001f13a
对象头是0x00007f7bd001f13a
加锁前对象处于无锁状态,加锁中处于轻量锁状态,同一时间再次访问同一锁后,轻量级锁膨胀为重量级锁
(4)无锁 =》偏向锁 =》重量锁
代码和SyncTest03一致,在VM options禁止延迟偏向锁的设置
-XX:BiasedLockingStartupDelay=0 -client -Xmx1024m -Xms1024m
输出结果:
未上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
第一次上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007fce8f96e005 (biased: 0x0000001ff3a3e5b8; epoch: 0; age: 0)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
第二次上锁,输出ClassLayout
com.tsj.threads.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007fce9801128a (fat lock: 0x00007fce9801128a)
8 4 (object header: class) 0xf800c143
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:
上锁前
mark标识:0x0000000000000005 (biasable; age: 0)
(1)biasable; age: 0
biasable:无锁可偏向
age:年龄为0
(2)0x0000000000000005
当前对象头为0x0000000000000005,二级制为:101
第一次上锁
mark标识:0x00007fce8f96e005 (biased: 0x0000001ff3a3e5b8; epoch: 0; age: 0)
(1)biased: 0x0000001ff3a3e5b8; epoch: 0; age: 0
biased:表示偏向锁
0x0000001ff3a3e5b8,二进制为:1111111110011101000111110010110111000
(2)0x00007fce8f96e005
当前对象头为0x00007fce8f96e005,二进制为:11111111100111010001111100101101110000000000101
第二次上锁
mark标识:0x00007fce9801128a (fat lock: 0x00007fce9801128a)
(1)fat lock: 0x00007fce9801128a
fat lock :表示重量级锁
0x00007fce9801128a ,表示上锁对象头,二进制为:11111111100111010011000000000010001001010001010,查看后两位为10,10表示重量级锁
(2)0x00007fce9801128a
表示当前对象头为0x00007fce9801128a,二进制为:11111111100111010011000000000010001001010001010
加锁前对象处于无锁状态,加锁中处于偏向锁,同一时间再次访问同一锁后,偏向锁膨胀为重量级锁
注意,在偏向锁状态,当前对象头和上锁的对象头往往不是同一个。
————————————————
版权声明:本文为CSDN博主「童小绿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tsj11514oo/article/details/127045106
网友评论