锁升级过程

对象布局

    在 hotspot 虚拟机中,对象在内存中布局可以被分为三部分:对象头/实例数据/补位数据。下面一张图是一个普通 java 对象和一个数组对象的结构组成:

锁升级过程_第1张图片

 

Java 对象大小计算

首先,对象头大小的确定

  • 在32位系统中,存放 Class 的指针空间大小为 4 字节,MarkWord 为 4 字节,即对象头为 8 字节
  • 在64 位系统中,存放 Class 指针的空间大小为 8 字节, MarkWord 为 8 字节,即对象头大小为 8 字节
  • 64 位系统下,如果开启了指针压缩,存放 Class指针的空间大小为 4 字节,MarkWord 为 8 字节,即对象头为 12 字节
  • 对于对象数据结构,参照上述三个规则,额外加上一个数组长度所含用的 4 个字节,就是最终对象头的大小
  • 计算对象的大小时,静态数据是不会被考虑进去的

MarkWord

标记字主要存储对象运行时的一部分数据。主要内容有 hashcode,GC 分代年龄,锁状态标志位,线程锁标记,偏向线程ID,偏向时间戳等。MarkWord 在32位和64位虚拟机上的大小分别位32bit 和 64bit,它的最后 2 bit 是锁标志位,用来标记当前对象的状态,具体如下:

状态 标志位 存储内容
未锁定 01 对象哈希码/对象分代年龄
轻量级锁定 00 指向锁记录的指针
膨胀(重量级锁定) 10 执行重量级锁定的锁指针
GC 标记 11 空(不需要记录信息)
可偏向 01 偏向线程id, 偏向时间戳,对象分代年龄

32 位 vm 在不同状态下 Markword 结构如下:

OBJECT HEADER   state
Mark word (32 bit) Class Word(32 bits)  
identity_hashcode:25 | age:4 | biased_lock:1 | lock:2 OOP to metadata object Normal
thread:23 | epoch:2 | age: 4 | biased_lock:1 | lock:2 OOP to metadata object Biased
ptr_to_lock_record: 30 | lock:2 OOP to metadata object Lightweight Locked
ptr_to_heavyweight_monitor: 30 | lock:2 OOP to metadata object Heavyweight Locked
| lock:2 OOP to metadata object Marked For GC

 

 

jol的使用


            org.openjdk.jol
            jol-core
            0.9
        

 

package kai.wu.dhwerbo.jol;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

/**
 * * *  GOOK LUCK  * *
 *
 * @Author: yunshan,
 * @Date: 2020/8/13.
 * @DESC:
 */
public class JolDemo {
    public static void main(String[] args) {

        Object o =  new Object();
        String s= ClassLayout.parseInstance(o).toPrintable();
        System.out.println(s);

//        synchronized (o) {
//            System.out.println(ClassLayout.parseInstance(o).toPrintable());
//        }
    }
}

 


# 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
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     A 0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     B 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     C 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
    D 12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


Process finished with exit code 0

如上图标志的ABCD中,

           AB属于对应头的MarkWold,可以看出MarkWold占8个bytes

           C属于classpointer 类型指针    可以根据VALUE,找到对应的class类对象Object.CLASS  占4个字节

          D属于补齐    4个字节

综上一个Object对象占16个字节 

 

锁升级的过程就是通过markWorld实现


# 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
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           90 f1 e2 02 (10010000 11110001 11100010 00000010) (48427408)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


Process finished with exit code 0

 

 

将线程休眠五秒


java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 48 33 03 (00000101 01001000 00110011 00000011) (53692421)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


Process finished with exit code 0

 

 

通过markwold的偏向锁位可以判断是属于哪一种锁状态

锁升级过程_第2张图片

001 无锁

101 偏向锁

00   轻量级锁

10  重量级锁

11   GC垃圾回收标志

锁升级过程_第3张图片

 

锁升级过程_第4张图片

从上面的两次结果比较可以看出,没有加synchronized的偏向位是001   加了synchronized后变成了101

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(并发编程)