Java分析Object Header 信息

1.头信息

1
2
3
class AAA{
private int number;
}
1
2
3
4
5
6
7
8
9
10
11
------------after invoke hascode()-----------------
AAA object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 bc 37 0b (00000001 10111100 00110111 00001011) (188201985)
4 4 (object header) 7e 00 00 00 (01111110 00000000 00000000 00000000) (126)
8 4 (object header) a8 35 85 1c (10101000 00110101 10000101 00011100) (478492072)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 4 int AAA.number 0
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

可以看到在 64位机上,关闭压缩。object header 占16 字节。以4个字节方式对齐。开启压缩,实测占12字节。

HotSpot 虚拟机的对象头包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针)

2.MarkWord

Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等。JVM 对象头一般占用两个机器码,在 32-bit JVM 上占用 64bit, 在 64-bit JVM 上占用 128bit 即 16 bytes(暂不考虑开启压缩指针的场景)。另外,如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通 Java 对象的元数据信息确定 Java 对象的大小,但是从数组的元数据中无法确定数组的大小。
对象需要存储的运行时数据很多,其实已经超出了32、64位 Bitmap 结构所能记录的限度,但是对象头信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例如在 32 位的HotSpot 虚拟机中对象未被锁定的状态下,Mark Word 的 32个Bits 空间中的 25Bits 用于存储对象哈希码(HashCode),4Bits 用于存储对象分代年龄,2Bits 用于存储锁标志位,1Bit固定为0,在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下对象的存储内容如下表所示。

原文链接:https://blog.csdn.net/wenniuwuren/article/details/50939410

img

来自 https://gist.github.com/arturmkrtchyan/43d6135e8a15798cc46c

64位机。关闭压缩 头部信息 各个字段占位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|------------------------------------------------------------------------------------------------------------|--------------------|
| Object Header (128 bits) | State |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| Mark Word (64 bits) | Klass Word (64 bits) | |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Normal |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Biased |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| ptr_to_lock_record:62 | lock:2 | OOP to metadata object | Lightweight Locked |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| ptr_to_heavyweight_monitor:62 | lock:2 | OOP to metadata object | Heavyweight Locked |
|------------------------------------------------------------------------------|-----------------------------|--------------------|
| | lock:2 | OOP to metadata object | Marked for GC |
|------------------------------------------------------------------------------|-----------------------------|--------------------|

64位机。开启压缩 头部信息 各个字段占位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|--------------------------------------------------------------------------------------------------------------|--------------------|
| Object Header (96 bits) | State |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| Mark Word (64 bits) | Klass Word (32 bits) | |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| unused:25 | identity_hashcode:31 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Normal |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| thread:54 | epoch:2 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | Biased |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| ptr_to_lock_record | lock:2 | OOP to metadata object | Lightweight Locked |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| ptr_to_heavyweight_monitor | lock:2 | OOP to metadata object | Heavyweight Locked |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|
| | lock:2 | OOP to metadata object | Marked for GC |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|

3.Klass Pointer,

即是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

4.通过JOL 验证 头部字段信息 。并分析字段信息。

1
2
3
4
5
6

01 bc 37 0b (00000001 10111100 00110111 00001011) (188201985)
7e 00 00 00 (01111110 00000000 00000000 00000000) (126)

a8 35 85 1c (10101000 00110101 10000101 00011100) (478492072)
00 00 00 00 (00000000 00000000 00000000 00000000) (0)

进一步拆分Mark Word (64 bits) 。对比各个字段。
unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2

由于大小端的关系,打印 hashcode可以看出是倒序的。

1
2
 unused:25                  | identity_hashcode:31              | unused:1     | age:4  | biased_lock:1 | lock:2
00000001 10111100 00110111 0|00010110 11111100 00000000 0000000 | 0 |0000 |0 | 00

看到age是4个bit,好像也可以解释为什么年龄最高为15了。 😂