使用JOL观测默认偏向锁
目录
- 一、对象头
- 二、使用Maven导入JOL相关Jar包
- 三、观察分析
- 1. 对象头格式
- 2. 测试观察
一、对象头
对象头有2个部分构成,一个是MarkWord,一个是KlassPoint。MarkWord记录对象的锁状态、分代年龄等对象信息。以下为64bitJVM的对象头MarkWord信息:
具体关于对象内存布局信息的知识,可以参见:Java对象的内存布局
本文主要介绍如何使用JOL去观察

二、使用Maven导入JOL相关Jar包
pom.xml
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.9</version></dependency>
测试:
public static void main(String[] args) throws IOException, InterruptedException {Integer i = Integer.valueOf(5);log.debug(ClassLayout.parseInstance(i).toPrintable());}
输出:
10:33:17.678 c.TestBiased [main] - java.lang.Integer object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 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) ae 22 00 20 (10101110 00100010 00000000 00100000) (536879790)12 4 int Integer.value 5
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
常用方法:
(1)查看对象内部信息: ClassLayout.parseInstance(obj).toPrintable()
(2)查看对象外部信息:包括引用的对象:GraphLayout.parseInstance(obj).toPrintable()
(3)查看对象占用空间总大小:GraphLayout.parseInstance(obj).totalSize()
三、观察分析
1. 对象头格式
如果开启了偏向锁(默认开启),那么对象创建后,markword 值为 0x05 即最后 3 位为 101,这时它的
thread、epoch、age 都为 0

2. 测试观察
因为偏向锁是默认是延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加 VM 参数 -XX:BiasedLockingStartupDelay=0 来禁用延迟
如果没有开启偏向锁,那么对象创建后,markword 值为 0x01 即最后 3 位为 001,这时它的 hashcode、age 都为 0
public static void main(String[] args) throws IOException, InterruptedException {test1();}// 测试偏向锁private static void test1() {Dog d = new Dog();//偏向锁延迟,所以创建完对象之后还是无锁状态log.debug(ClassLayout.parseInstance(d).toPrintable());try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}//延迟4s之后,输出偏向锁状态log.debug(ClassLayout.parseInstance(new Dog()).toPrintable());}class Dog {}
10:33:17.673 c.TestBiased [main] - cn.itcast.n4.Dog object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 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) a4 8b 01 20 (10100100 10001011 00000001 00100000) (536972196)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total10:33:22.679 c.TestBiased [main] - cn.itcast.n4.Dog object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 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) a4 8b 01 20 (10100100 10001011 00000001 00100000) (536972196)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
这里使用JOL打印的数据是以字节为单位进行逆序输出的。比如说:
在开启偏向锁的情况下MarkWord的最后3位应该是101,根据对象头的格式,前8个字节为MardWord(在64位JVM下)。
所以应该为:
0 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000101) (5)
倒序输出,为:
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)
也可以通过KlassPoint的内容进行具体验证。如下:
8 4 (object header) a4 8b 01 20 (10100100 10001011 00000001 00100000) (536972196)

可以看到,真实的十六进制的KlassPoint为: 20 01 8b a4,但是打印输出为:a4 8b 01 20
注:至于为什么64位虚拟机的KlassPoint为32bit而不是64bit,是因为JVM默认开启了地址压缩
通过打印默认参数可以观察到:
java -XX:+PrintCommandLineFlags -version

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
