探究java对象头
探究java对象头
研究java对象头,我这里先截取Hotspot中关于对象头的描述,本文研究基于64-bit HotSpot VM
文件路径 openjdk-jdk8u-jdk8u\hotspot\src\share\vm\oops\markOop.hpp
// 32 bits:
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ------------------------------------------>| (CMS free block)
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
// size:64 ----------------------------------------------------->| (CMS free block)
//
// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
一:java对象组成 : 对象头(mark word 和 klass Pointer,如果是数组,包含数组长度)、实例化数据、对齐填充
借助openJdk中的工具类JOL来分析java对象布局 maven的pom.xml中添加依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
Test1:
public class A {
boolean flag = false ;
} ------------------------------------------------------------
public class Current{
public static void main(String[] args) {
A obj = new A();
A[] b = new A[10];
System.out.println(VM.current().details());
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
System.out.println(ClassLayout.parseInstance(b).toPrintable());
}
} 运行结果:
# Running 64-bit HotSpot VM.
# Using compressed oop with 0-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
com.yew.A 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) 43 a1 f9 27 (01000011 10100001 11111001 00100111) (670671171)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
[Lcom.yew.A; 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) 81 a1 f9 27 (10000001 10100001 11111001 00100111) (670671233)
12 4 (object header) 0a 00 00 00 (00001010 00000000 00000000 00000000) (10)
16 40 com.yew.A A;.<elements> N/A
Instance size: 56 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Test1分析:普通对象总共16B,对象头占用12B,另外4B(64位虚拟机上对象的大小必须是8的倍数)为对齐填充字节。
Hotspot中的重要术语:
mark word
The first word of every object header. Usually a set of bitfields including synchronization state and identity hash code. May also be a pointer (with characteristic low bit encoding) to synchronization related information. During GC, may contain GC state bits.
每个对象头的第一个word。通常是一组位字段,包括同步状态和标识哈希值。也可以是指向同步相关信息的指针(具有特征性的低位编码)。在GC期间,可以包含GC状态位
klass pointer
The second word of every object header. Points to another object (a metaobject) which describes the layout and behavior of the original object. For Java objects, the "klass" contains a C++ style "vtable".
klass word为对象头的第二个word,主要指向对象的元数据;
object header
Common structure at the beginning of every GC-managed heap object. (Every oop points to an object header.) Includes fundamental information about the heap object's layout, type, GC state, synchronization state, and identity hash code. Consists of two words. In arrays it is immediately followed by a length field. Note that both Java objects and VM-internal objects have a common object header format.
对象头由两个word组成,每个GC管理堆对象的开头都存在这样一个公共结构。(每个oop都指向一个对象头)包含有关堆对象的布局、类型、GC状态、同步状态和哈希值的基本信息。在数组中,后面紧接着是一个长度字段。注意Java对象和VM内部对象都有一个通用的对象头格式。
二:java对象头
64位对象头由Mark Word、klass pointer两部分组成,如果对象是数组,则还要加上数组长度,即三部分组成。
Mark Word由64位8个字节组成,klass pointer由64位8个字节组成,但我们使用的64位 JVM会默认使用选项 +UseCompressedOops 开启指针压缩,将指针压缩至32位。即上面截图中的klass pointer为4个字节32位。这里重点描述下Mark Word部分。
Mark Word的64位,不同的位表示的意思不一样,具体如下所示:
|--------------------------------------------------------------------------------------------------------------|
| Object Header (128 bits) |
|--------------------------------------------------------------------------------------------------------------|
| Mark Word (64 bits) | Klass Word (64 bits) |默认开启指针压缩
|--------------------------------------------------------------------------------------------------------------|
|unused:25|identity_hashcode:31(56) | 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
|--------------------------------------------------------------------------------------------------------------|
对象在无锁的情况下,前56位为对象的hashCode值,下面为验证代码Test2:
public class Current{
public static void main(String[] args) throws Exception {
A obj = new A();
out.println("before hash");
out.println(ClassLayout.parseInstance(obj).toPrintable());
out.println("JVM hash==="+Integer.toHexString(obj.hashCode()));
out.println("after hash");
countHash(obj);
out.println(ClassLayout.parseInstance(obj).toPrintable());
} public static void countHash(Object obj) throws Exception {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
long hashCode = 0;
for (long index = 7; index > 0; index--) {
hashCode |= (unsafe.getByte(obj, index) & 0xFF) << ((index-1) * 8);
}
String code = Long.toHexString(hashCode);
out.println("util 0x===="+code);
}
} 执行结果:
before hash
com.yew.A 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) 43 21 ed 27 (01000011 00100001 11101101 00100111) (669851971)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
JVM hash===368102c8
after hash
util 0x====368102c8
很明显:此处得到的值与对象的hashCode值相等
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 c8 02 81 (00000001 11001000 00000010 10000001) (-2130524159)
4 4 (object header) 36 00 00 00 (00110110 00000000 00000000 00000000) (54)
8 4 (object header) 43 21 ed 27 (01000011 00100001 11101101 00100111) (669851971)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
Test2分析:因为对象字节采用小端存储,所以无锁状态2-7字节存放的是对象的Hashcode值,那么第一个字节8位存放的是分代年龄、偏向锁信息,和对象状态
2.1 无锁
public class NoLock {
public static void main(String[] args) {
A a = new A();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
a.hashCode();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
执行结果:
com.yew.A 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) 43 21 f6 27 (01000011 00100001 11110110 00100111) (670441795)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 c8 02 81 ( 11001000 00000010 10000001) (-2130524159)
4 4 (object header) 36 00 00 00 (00110110 00000000 00000000 00000000) (54)
8 4 (object header) 43 21 f6 27 (01000011 00100001 11110110 00100111) (670441795)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
分析结果:当一个对象才new且调用了hashcode方法后(如果不调用hashcode方法,那么存放hashcode的31位全部为0),正常情况下处于无锁状态,无锁状态时,Mark Word的64位分别为:前25位未使用,接下来的31位为对象的hashcode,接下来的1位未使用,接下来的4位表示对象的GC年龄,接下来的一位为偏向锁状态,最后2位表示锁状态,如上图所示。
2.2 偏向锁
偏向锁:1.保证线程安全;2.不存在资源竞争
public class BiasedLock {
public static void main(String[] args) /**throws InterruptedException**/ {
// Thread.sleep(4000);
// Thread.sleep(5000);
A a = new A();
System.out.println("before lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
synchronized (a){
System.out.println("locking...........");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
System.out.println("after lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
执行结果如下:
before lock
com.yew.A 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) 43 c1 fa 27 (01000011 11000001 11111010 00100111) (670744899)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
locking...........
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) e8 f0 6c 02 ( 11110000 01101100 00000010) (40693992)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 fa 27 (01000011 11000001 11111010 00100111) (670744899)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
after lock
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 ( 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 fa 27 (01000011 11000001 11111010 00100111) (670744899)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
测试分析:根据执行结果分析,对象a并没有成为偏向锁,而是由 无锁-轻量锁-无锁。因为上述案例仅有一个线程调用synchronized,预期为偏向锁,但是实际运行与预期不符,根据查询资料发现,虚拟机在启动的时候会延迟开启偏向锁(时间约为4300ms),便于测试,可以通过设置JVM参数关闭偏向锁的延迟加载。IDEA设置方式:Run-->Edit Configurations->VM Options -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0,再次运行可得结果。
before lock
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 ( 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 fd 27 (01000011 11100001 11111101 00100111) (670949699)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
此时占用 thread 和 epoch 的 位置的均为0,说明当前偏向锁并没有偏向任何线程。此时这个偏向锁正处于可偏向状态,准备好进行偏向了!你也可以理解为此时的偏向锁是一个特殊状态的无锁
locking...........
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 f0 27 02 ( 11110000 00100111 00000010) (36171781)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 fd 27 (01000011 11100001 11111101 00100111) (670949699)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
synchronized(a),对a加锁后,对象a偏向了某个线程,所以2-8位表示的是线程的ID标识,所以显然此时对象a已经成为偏向锁。
after lock
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 f0 27 02 ( 11110000 00100111 00000010) (36171781)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 fd 27 (01000011 11100001 11111101 00100111) (670949699)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
退出同步代码块,依然是偏向锁
睡眠5s或者关闭偏向锁延迟加载时 偏向锁(可偏向)--->偏向锁(偏向线程)--->偏向锁
2.3 轻量锁
public class LightLock {
public static void main(String[] args) {
A a = new A();
synchronized (a){
System.out.println("locking......");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
}
locking......
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 28 f4 ef 02 ( 11110100 11101111 00000010) (49280040)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 f0 27 (01000011 11100001 11110000 00100111) (670097731)
12 1 boolean A.flag false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
结果分析:JVM默认开启偏向锁延迟加载,所以当使用synchronized给对象加锁时,该对象会膨胀为轻量锁。
2.4 重量锁
重量锁:当存在线程竞争同一把锁时,就会由轻量锁膨胀为重量级锁;
public class WeightLock {
static A a = new A();
public static void main(String[] args) throws InterruptedException {
System.out.println("before lock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//无锁
new Thread(new Runnable(){
@Override
public void run() {
synchronized (a){
System.out.println("once locking");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread release");
}
}
}).start();
Thread.sleep(1000);
System.out.println("main printLock");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
synchronized (a){
System.out.println("second locking");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//重量锁
}
System.out.println("after locking");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//重量锁
System.gc();
System.out.println("after gc");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//gc标记
}
}
执行结果:
before lock
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 ( 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
once locking
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) b0 f1 e2 0b ( 11110001 11100010 00001011) (199422384)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
main printLock
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) b0 f1 e2 0b ( 11110001 11100010 00001011) (199422384)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
thread release
second locking
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ca 9f ac 08 ( 10011111 10101100 00001000) (145530826)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
after locking
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ca 9f ac 08 ( 10011111 10101100 00001000) (145530826)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
after gc
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 09 00 00 00 ( 00000000 00000000 00000000) (9)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0a 07 1e (00011000 00001010 00000111 00011110) (503777816)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Biased_lock(1bits) |
Lock(2bits) |
description |
0 |
01 |
无锁 |
1 |
01 |
偏向锁 |
0 |
00 |
轻量锁 |
0 |
10 |
重量锁 |
0 |
01 |
无锁--GC标记 |
三:偏向锁/轻量级锁/重量级锁
上述三种锁是指锁的状态,并且是针对Synchronized。通过引入锁升级的机制来实现高效Synchronized。锁的状态是通过对象监视器在对象头中的字段来表明的。
偏向锁:一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
轻量级锁:当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁:当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让它申请的线程进入阻塞,性能降低。
自旋锁:自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
三:性能比较
3.1 偏向锁和轻量锁的性能对比
//偏向锁 关闭偏向锁延迟加载
//VM Options -XX:BiasedLockingStartupDelay=0
@Test
public void testBiasedLock(){
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000 ; i++) {
synchronized (a){
count++;
}
}
long end = System.currentTimeMillis();
System.out.println("耗时为:"+(end-start)+"ms");
System.out.println(count);
}
//轻量锁
@Test
public void testLightLock(){
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000 ; i++) {
synchronized (a){
count++;
}
}
long end = System.currentTimeMillis();
System.out.println("耗时为:"+(end-start)+"ms");//36742ms
System.out.println(count);
}
//重量锁
@Test
public void testWeightLock(){
A a = new A();
long start = System.currentTimeMillis();
for (int i = 0; i < 2; i++) {
new Thread(a::parse, "t" + i).start();
}
System.out.println(Thread.activeCount());
while (Thread.activeCount()>2){
Thread.yield();
}
long end = System.currentTimeMillis();
System.out.println("耗时为:"+(end-start)+"ms");//50727ms
System.out.println(a.getI());
}
锁的状态 |
偏向锁(B) |
轻量锁(L) |
重量锁(W) |
性能比较 |
耗时 |
4424ms |
36742ms |
50727ms |
B>L>W |
四:其他
4.1 对象计算过哈希后无法重新偏向
//关闭偏向锁延迟加载 -XX:BiasedLockingStartupDelay=0
public class HashLockTest {
static A a = new A();
public static void main(String[] args) {
System.out.println("before hash");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//可偏向
a.hashCode();//计算hashcode
synchronized (a){
System.out.println("after hash");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
}
System.out.println(ClassLayout.parseInstance(a).toPrintable());//无锁
}
}
4.2 调用wait方法--->重量锁
public class WaitLockTest {
static A a = new A();
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (a){
System.out.println("before wait");
System.out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
try {
a.wait();
} catch (InterruptedException e) {
}
System.out.println("after wait");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
}).start();
Thread.sleep(7000);
synchronized (a){
a.notify();
}
}
}
执行结果:
before wait
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 90 f6 04 0b (10010000 11110110 00000100 00001011) (184874640)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 ed 27 (01000011 11100001 11101101 00100111) (669901123)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
after wait
com.yew.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 9a 95 86 08 ( 10010101 10000110 00001000) (143037850)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 e1 ed 27 (01000011 11100001 11101101 00100111) (669901123)
12 4 int A.i 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
探究java对象头的更多相关文章
- JAVA对象头详解(含32位虚拟机与64位虚拟机)
为什么要学习Java对象头 学习Java对象头主要是为了解synchronized底层原理,synchronized锁升级过程,Java并发编程等. JAVA对象头 由于Java面向对象的思想,在JV ...
- 并发王者课-青铜5:一探究竟-如何从synchronized理解Java对象头中的锁
在前面的文章<青铜4:synchronized用法初体验>中,我们已经提到锁的概念,并指出synchronized是锁机制的一种实现.可是,这么说未免太过抽象,你可能无法直观地理解锁究竟是 ...
- 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现
一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...
- 盘一盘 synchronized (一)—— 从打印Java对象头说起
Java对象头的组成 Java对象的对象头由 mark word 和 klass pointer 两部分组成, mark word存储了同步状态.标识.hashcode.GC状态等等. klass ...
- java对象头信息和三种锁的性能对比
java头的信息分析 首先为什么我要去研究java的对象头呢? 这里截取一张hotspot的源码当中的注释 这张图换成可读的表格如下 |-------------------------------- ...
- JVM源码分析之Java对象头实现
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Java对象头实现 HotSpot虚拟机中,对象在内存中的布局分为三 ...
- JAVA对象头
#为了防止自己忘记,先记着,之前我一直以为<深入理解JAVA虚拟机>写错了来着. 一. JAVA对象 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header ...
- jvm源码解析java对象头
认真学习过java的同学应该都知道,java对象由三个部分组成:对象头,实例数据,对齐填充,这三大部分扛起了java的大旗对象,实例数据其实就是我们对象中的数据,对齐填充是由于为了规则分配内存空间,j ...
- Java 对象头那点事
概览 对象头 存放:关于堆对象的布局.类型.GC状态.同步状态和标识哈希码的基本信息.Java对象和vm内部对象都有一个共同的对象头格式. (后面做详细介绍) 实例数据 存放:类的数据信息,父类的信息 ...
随机推荐
- Java实现单链表反转操作
单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据.二是指针域,用于存储下一个节点的地址.在Java中定义如下: public class ...
- [Go] gocron源码阅读-通过第三方cli包实现命令行参数获取和管理
gocron源码中使用的是下面这个第三方包来实现的,下面就单独的拿出来测试以下效果,和官方flag包差不多 go get github.com/urfave/cli package main impo ...
- [日常] 解决docker拉取镜像速度慢的问题
将docker修改为国内镜像源 在/etc/docker/daemon.json文件中添加下面参数 此处使用的是中国科技大学的docker镜像源 { "registry-mirrors ...
- itest(爱测试) 4.1.5 发布,开源BUG 跟踪管理 & 敏捷测试管理软件
v4.1.5下载地址 :itest下载 itest 简介:查看简介 itest 开源敏捷测试管理,testOps 践行者.可按测试包分配测试用例执行,也可建测试迭代(含任务,测试包,BUG)来组织测试 ...
- 30.Java基础_接口_抽象类_具体类实现案例
public interface SpeakEnglish { public abstract void speak(); } public abstract class Person { priva ...
- luoguP3071 [USACO13JAN]座位Seating
https://www.luogu.org/problem/P3071 AC代码: https://www.luogu.org/blog/user33426/solution-p3071 莫名其妙RE ...
- Linux学习(一)简介
Linux 简介 Linux 内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的. Linux 是一套免费使用和自由传播的类 Unix 操作系统 ...
- web-never give up
打开题目连接 ?id=1 ,疑是注入点 但是输入其他数字无果 打开源码,发现注释有网页链接 打开连接123.206.87.240:8006/test/1p.html 发现回到了bugku的论坛首页,应 ...
- day69_10_14 drf接口框架。
一.drf框架简介 drf全程是:django-rest framework. 其中涉及的知识点有. 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下 ...
- day57 choise字段与ajax
一.choice字段. 在django的orm中,创建如同性别,民.族等可选择的字段时,可以选择使用choice字段进行定义. 这样的定义可以使用简单的数字代替数据量大的字符,减少数据库的负担. ch ...