java对象头信息分析
从JVM源码中可知(markOop.hpp文件中)
可以转换成这样的表格形式
image.png
可以表示成下面这样
无锁: unused(25) hashcode(31) unused(1) age(4) biased_lock(1) lock(2)
偏向锁:thread(54) epoch(2) unused(1) age(4) biased_lock(1) lock(2)
轻量级锁: ptr_to_lock_record(62) lock(2)
重量级锁: ptr_to_heavyweight_monitor(62) lock(2)
Object Header 一共128btis(16字节),klass部分可以压缩。压缩成12字节bytes
对象头包含两个部分-------mark word (64bits 8字节)和klass word(32bits 4字节)
可参考http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html
image.png
mark word包括:hashcode哈希值、age表示gc年龄、blased_lock是否可偏向、lock锁的标识位
klass word:对象指针、填充区域
JOL来分析java的对象布局
加入依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
对象头
示例代码
package com.thread;
public class A {
}
package com.thread;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class MyJolTest1 {
public static void main(String[] args) {
System.out.println( VM.current().details());
System.out.println( ClassLayout.parseClass(A.class).toPrintable());
}
}
image.png
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]对应[Oop(Ordinary Object Pointer), boolean, byte, char,short, int, float, long, double]大小
boolean值在对象头展现
示例代码2
package com.thread;
public class A {
boolean flag =false;
}
package com.thread;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class MyJolTest2 {
public static void main(String[] args) {
System.out.println( VM.current().details());
System.out.println( ClassLayout.parseClass(A.class).toPrintable());
}
}
image.png
16字节没有改变,其中对象头12字节
hashcode位置
001无锁
package com.thread;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class MyJolTest3 {
public static void main(String[] args) {
A a= new A();
System.out.println("befor hash");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
//计算的hashcode
System.out.println("-----------hashCode="+Integer.toHexString(a.hashCode()));
System.out.println("after hash");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
证明hashcode值是这31位
image.png
偏向锁101
示例代码4
package com.thread;
import org.openjdk.jol.info.ClassLayout;
public class MyJolTest4 {
static A a;
public static void main(String[] args) throws Exception {
Thread.sleep(5000);
a = new A();
System.out.println( "befre lock" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
sync();
System.out.println( "after lock" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
}
public static void sync() throws InterruptedException {
synchronized (a) {
System.out.println( "================" );
}
}
}
00000101 偏向
Thread.sleep(5000);代表可偏向,也可以修改启动参数XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
image.png
轻量级锁000
示例代码5
package com.thread;
import org.openjdk.jol.info.ClassLayout;
public class MyJolTest5 {
static A a;
public static void main(String[] args) throws Exception {
a = new A();
System.out.println("befre lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
sync();
System.out.println("after lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
public static void sync() throws InterruptedException {
synchronized (a){
System.out.println("lock ing");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
}
从无锁到轻量级锁再到释放锁
image.png
image.png
重量级锁010
示例代码
package com.thread;
import org.openjdk.jol.info.ClassLayout;
public class MyJolTest6 {
static A a;
public static void main(String[] args) throws Exception {
a = new A();
System.out.println( "befre lock" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
Thread t1 = new Thread() {
public void run() {
synchronized (a) {
try {
Thread.sleep( 5000 );
System.out.println( "t1 release" );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread.sleep( 1000 );
System.out.println( "t1 lock ing" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
sync();
System.gc();
System.out.println( "after gc()" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
}
public static void sync() throws InterruptedException {
synchronized (a) {
System.out.println( "t1 main lock" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
}
}
}
示例代码持有锁的变化状态 无锁--轻量级锁--重量级锁--gc释放无锁
image.png
image.png
wait方法调用,变成重量级锁
示例代码
package com.thread;
import org.openjdk.jol.info.ClassLayout;
public class MyJolTest7 {
static A a;
public static void main(String[] args) throws Exception {
Thread.sleep(5000);
a = new A();
System.out.println("befre lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
Thread t1= new Thread(){
public void run() {
synchronized (a) {
try {
System.out.println( "before wait" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
a.wait();
System.out.println( " after wait" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread.sleep(5000);
synchronized (a) {
a.notifyAll();
}
}
}
image.png
image.png
计算hashcode之后,不可偏向
示例代码
package com.thread;
import org.openjdk.jol.info.ClassLayout;
public class MyJolTest8 {
static A a;
public static void main(String[] args) throws Exception {
Thread.sleep( 5000 );
a = new A();
System.out.println( Integer.toHexString( a.hashCode() ) );
System.out.println( "befre lock" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
Thread t1 = new Thread() {
public void run() {
synchronized (a) {
System.out.println( "lock ed" );
System.out.println( ClassLayout.parseInstance( a ).toPrintable() );
}
}
};
t1.start();
}
}
image.png
总结:
主要展现java中的锁在对象头中的状态
偏向锁(101)、无锁(001)、轻量级锁(000)、重量级锁(010)、gc(011)
轻量级锁是交替持有锁(不存在竞争),而重量级锁是互斥持有
网友评论