java对象的内存布局

一、对象在内存中的存储布局

对象的内存布局分为两种,普通对象和数组对象
在这里插入图片描述

在这里插入图片描述

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、进制工具

https://hex.buyaocha.com/

三、实验

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
|--------------------------------------------------------------------------------------------------------------|
————————————————

lock: 锁状态标记位,该标记的值不同,整个mark word表示的含义不同。

biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。

从分布可以得出,看锁标记,直接看后 3 位即可,如果给到你锁类型标识,你只需要看前后2位就行。

biased_locklock16进制状态
0011无锁
1015偏向
0000轻量
0102重量
0113GC

(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: 01)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:表示无锁且不可偏向
	(20x0000000000000001,
		对象头:0x0000000000000001,二进制表示为:1。
	
上锁后:
	mark标识:0x0000700004f9e9b0 (thin lock: 0x0000700004f9e9b0)1)thin lock: 0x0000700004f9e9b0
		thin lock:表示轻量级锁;
		上锁的对象头:0x0000700004f9e9b0,二进制表示为:11100000000000000000100111110011110100110110000,看后两位表示:0000:表示轻量级锁
	(20x0000700004f9e9b0
	对象头是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:年龄:020x0000000000000005
		对象头是0x0000000000000005,二进制表示为:101。
		
上锁后:
	mark标识:0x00007f9c7e0d3005 (biased: 0x0000001fe71f834c; epoch: 0; age: 0)1)biased: 0x0000001fe71f834c; epoch: 0; age: 0
		biased:表示偏向锁
		上锁的对象:0x0000001fe71f834c,二进制表示为:1111111100111000111111000001101001100,看后三位表示:1001:表示偏向锁,00:表示轻量级锁
		age:年龄:0
		如果开启了偏向锁,thread、epoch、age 都为 020x00007f9c7e0d3005
		对象头是: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,看后两位表示:0000:表示轻量级锁
(20x0000700008ebc9b0
	对象头是:0x0000700008ebc9b0

第二次还是对同一把锁方法,存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。
mark标识为:0x00007f7bd001f13a (fat lock: 0x00007f7bd001f13a)1)fat lock: 0x00007f7bd001f13a
	fat lock :表示重量级锁
	0x00007f7bd001f13a,上锁的对象头,二进制为:11111110111101111010000000000011111000100111010,看后两位表示:0101:表示轻量级锁
(20x00007f7bd001f13a
	对象头是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:年龄为020x0000000000000005
	当前对象头为0x0000000000000005,二级制为:101

第一次上锁
mark标识:0x00007fce8f96e005 (biased: 0x0000001ff3a3e5b8; epoch: 0; age: 0)1)biased: 0x0000001ff3a3e5b8; epoch: 0; age: 0
	biased:表示偏向锁
	0x0000001ff3a3e5b8,二进制为:111111111001110100011111001011011100020x00007fce8f96e005 
	当前对象头为0x00007fce8f96e005,二进制为:11111111100111010001111100101101110000000000101

第二次上锁
mark标识:0x00007fce9801128a (fat lock: 0x00007fce9801128a)1)fat lock: 0x00007fce9801128a
	fat lock :表示重量级锁
	0x00007fce9801128a ,表示上锁对象头,二进制为:11111111100111010011000000000010001001010001010,查看后两位为1010表示重量级锁
(20x00007fce9801128a 
	表示当前对象头为0x00007fce9801128a,二进制为:11111111100111010011000000000010001001010001010

加锁前对象处于无锁状态,加锁中处于偏向锁,同一时间再次访问同一锁后,偏向锁膨胀为重量级锁
注意,在偏向锁状态,当前对象头和上锁的对象头往往不是同一个。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值