一、对象布局
1、对象头
1)存储对象自身的运行时数据 hash码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。占位32/64位虚拟机分别占32/64个比特,官方称
"Mark Word"
2)类型指针 指向对象的元数据,如果是数组,还会存储数组长度。
2、实例数据
3、对齐填充
要求对象是8的整数倍,对象头已经是8位的整数倍,只填充实例数据即可。
二、Object o = new Object()内存占用情况
占用16个字节 对象头12个字节,对齐填充4个字节,共16个
使用ClassLayout进行查看内存布局 maven
代码语言:javascript复制<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
代码语言:javascript复制Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
输出结果
代码语言:javascript复制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
三、查看锁的标记位
1652873201(1).png
锁升级过程 1、无锁状态(001) 2、无锁 ->偏向锁 : 给普通对象加个synchronized,初始就是偏向锁(101) 3、偏向锁 -> 自旋锁(轻量级锁 00),JVM发现有第二个线程去竞争该锁,变成自旋锁(轻量级锁 00) 4、自旋锁 -> 重量级锁 : 当JVM发现线程竞争激烈的时候,就把自旋锁升级为重量级锁。判断标准有两个,一个是自旋超过10次,另一个是wait的线程个数超过CPU的一半。
1、未锁定=>轻量级锁定
代码语言:javascript复制 public static void main(String[] args) {
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
2、轻量级锁=>重量级锁
代码语言:javascript复制 @SneakyThrows
public static void main(String[] args) {
Object o = new Object();
System.out.println("new ---" ClassLayout.parseInstance(o).toPrintable());
new Thread(() -> {
synchronized (o) {
System.out.println("Thread 1 -- " ClassLayout.parseInstance(o).toPrintable());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
new Thread(() -> {
synchronized (o) {
System.out.println("Thread 2 -- " ClassLayout.parseInstance(o).toPrintable());
}
}).start();
}