HotSpot 中 java 对象头
1.相关文档
官 方 文 档 |
Java HotSpot VM Options | https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html |
open jdk 18 mark word源码 |
https://github.com/openjdk/jdk18/blob/master/src/hotspot/share/oops/markWord.hpp |
|
open jdk 18 klass word源码 |
https://github.com/openjdk/jdk18/blob/master/src/hotspot/share/oops/klass.hpp |
|
关于klass将被移除的草案 |
||
open jdk 15 mark word源码 |
https://github.com/openjdk/jdk15/blob/e208d9aa1f185c11734a07 |
|
Deprecate and Disable Biased Locking | https://openjdk.java.net/jeps/374 | |
其 它 文 档 |
baeldung | https://www.baeldung.com/java-memory-layout |
2.对象头
一个java对象在内存中除了有自身成员属性外,还有 锁信息、Hash码、对象年龄,class信息、数组长度等数据,它们称为对象头信息。
在HotSpot虚拟机中,对象头包含2个部分:
- mark word : 保存hashcode、锁信息、偏向锁状态、gc信息。
- class word :一个指针,指向本类元数据,它里面保存类的信息:类名、基类、修饰符等
- 数组长度 : 当变量为数组时,还要一个空间存放数组的长度。
3.查看jvm信息
@Test
public void jvm() {
out.println(VM.current().details());
}
结果:
# WARNING: Unable to get Instrumentation. Dynamic Attach failed. You may add this JAR as -javaagent manually, or supply -Djdk.attach.allowAttachSelf
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# 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]
其中后两行 (4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] )含义如下:
\ | 引用 | booleans | byte | short | chars | int | float | long | double |
普通对象 | 4 | 1 | 1 | 2 | 2 | 4 | 4 | 8 | 8 |
数组 | 4 | 1 | 1 | 2 | 2 | 4 | 4 | 8 | 8 |
HotSpot JVM 默认启用了指针压缩(-XX:+UseCompressedOops),所以引用的大小是4,未启用(-XX:-UseCompressedOops)时引用的大小是8。
4. mark word 信息
HotSpot 中对象按大端保存数据。保存hashcode、锁信息、偏向锁状态、gc信息。
4.1 open jdk 18 word
https://github.com/openjdk/jdk18/blob/master/src/hotspot/share/oops/markWord.hpp
// The markWord describes the header of an object.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
// 32 bits:
// --------
// hash:25 ------------>| age:4 unused_gap:1 lock:2 (normal object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused_gap:1 age:4 unused_gap:1 lock:2 (normal object)
//
// - hash contains the identity hash value: largest value is
// 31 bits, see os::random(). Also, 64-bit vm's require
// a hash value no bigger than 32 bits because they will not
// properly generate a mask larger than that: see library_call.cpp
//
// - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
// [ptr | 00] locked ptr points to real header on stack
// [header | 01] unlocked regular object header
// [ptr | 10] monitor inflated lock (header is wapped out)
// [ptr | 11] marked used to mark an object
// [0 ............ 0| 00] inflating inflation in progress
//
// We assume that stack/thread pointers have the lowest two bits cleared.
//
// - INFLATING() is a distinguished markword value of all zeros that is
// used when inflating an existing stack-lock into an ObjectMonitor.
// See below for is_being_inflated() and INFLATING().
32 位机器:(大端)
00000101 00000000 00000000 0 | 0000 | 0 | 00 |
hash(25位) | gc age(4位) | unused_gap(1位) | lock(2位) |
64位机器:(大端)
00000000 00000000 00000000 0 | 00000000 00000000 00000000 0000000 | 0 | 0000 | 0 | 00 |
unused:25 | hash:31 | unused_gap:1 | age:4 | unused_gap:1 | lock(2位) |
其中 :
- hash :位保存hash值,无论32位机器还是64位机器,最大到31位。
- age : 如果对象在Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。
- gap : 空白位
- lock :锁状态标记位
- unused:未使用位
[ptr | 00] | locked | ptr points to real header on stack |
[header | 01] | unlocked | regular object header |
[ptr | 10] | monitor | inflated lock (header is wapped out) |
[ptr | 11] | marked | used to mark an object |
[0 ............ 0| 00] | inflating | inflation in progress |
4.2 open jdk 15 word
// The markWord describes the header of an object.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
// 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)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused_gap:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused_gap:1 age:4 biased_lock:1 lock:2 (biased object)
//
// - hash contains the identity hash value: largest value is
// 31 bits, see os::random(). Also, 64-bit vm's require
// a hash value no bigger than 32 bits because they will not
// properly generate a mask larger than that: see library_call.cpp
// and c1_CodePatterns_sparc.cpp.
//
// - the biased lock pattern is used to bias a lock toward a given
// thread. When this pattern is set in the low three bits, the lock
// is either biased toward a given thread or "anonymously" biased,
// indicating that it is possible for it to be biased. When the
// lock is biased toward a given thread, locking and unlocking can
// be performed by that thread without using atomic operations.
// When a lock's bias is revoked, it reverts back to the normal
// locking scheme described below.
//
// Note that we are overloading the meaning of the "unlocked" state
// of the header. Because we steal a bit from the age we can
// guarantee that the bias pattern will never be seen for a truly
// unlocked object.
//
// Note also that the biased state contains the age bits normally
// contained in the object header. Large increases in scavenge
// times were seen when these bits were absent and an arbitrary age
// assigned to all biased objects, because they tended to consume a
// significant fraction of the eden semispaces and were not
// promoted promptly, causing an increase in the amount of copying
// performed. The runtime system aligns all JavaThread* pointers to
// a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
// to make room for the age bits & the epoch bits (used in support of
// biased locking).
//
// [JavaThread* | epoch | age | 1 | 01] lock is biased toward given thread
// [0 | epoch | age | 1 | 01] lock is anonymously biased
//
// - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
// [ptr | 00] locked ptr points to real header on stack
// [header | 0 | 01] unlocked regular object header
// [ptr | 10] monitor inflated lock (header is wapped out)
// [ptr | 11] marked used to mark an object
//
// We assume that stack/thread pointers have the lowest two bits cleared.
32位:(大端)
00000000 00000000 00000000 0 | 0000 | 0 | 00 |
hash:25 | age:4 | biased_lock:1 | lock:2 |
00000000 00000000 0000000 | 00 | 0000 | 0 | 00 |
JavaThread*:23 | epoch:2 | age:4 | biased_lock:1 | lock:2 |
64位:(大端)
00000000 00000000 00000000 0 | 00000000 00000000 00000000 0000000 | 0 | 0000 | 0 | 00 |
unused:25 | hash:31 | unused_gap:1 | age:4 | biased_lock:1 | lock:2 |
00000000 00000000 00000000 00000000 00000000 00000000 000000 | 00 | 0 | 0000 | 0 | 00 |
JavaThread*:54 | epoch:2 | unused_gap:1 | age:4 | biased_lock:1 | lock:2 |
其中:
- hash :位保存hash值,无论32位机器还是64位机器,最大到31位。
- age : 如果对象在Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。
- gap : 空白位
- biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁
- lock :锁状态标记位
- JavaThread*:持有偏向锁的线程指针。
- epoch:偏向时间戳
4.3 open jdk 18 与 15 区别
对比发现:
- open jdk18 中不在对象头里区分biased_object还是normal object,默认不打开biased locking.可通过XX:+UseBiasedLocking打开。
- 没有了 biased_lock、epoch、JavaThread*
- 具体参见 源码:https://github.com/openjdk/jdk18
详细可参看官方文档:
https://openjdk.java.net/jeps/374
4.4 hash值示例
@Test
public void hash(){
class A {}
final A a = new A();
ClassLayout layout = ClassLayout.parseInstance(a);
out.println(VM.current().details());
out.println("**** Fresh object");
out.println(layout.toPrintable());
out.println("hashCode: " + Integer.toHexString(a.hashCode()));
out.println();
out.println("**** After identityHashCode()");
out.println(layout.toPrintable());
}
结果
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# 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]
**** Fresh object
com.example.sjjg.java.ObjectLayout$8A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
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)
8 4 (object header) a3 63 03 20 (10100011 01100011 00000011 00100000) (537093027)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$8A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
hashCode: 455b6df1
**** After identityHashCode()
com.example.sjjg.java.ObjectLayout$8A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 f1 6d 5b (00000001 11110001 01101101 01011011) (1533931777)
4 4 (object header) 45 00 00 00 (01000101 00000000 00000000 00000000) (69)
8 4 (object header) a3 63 03 20 (10100011 01100011 00000011 00100000) (537093027)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$8A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
当调用对象的hashCode()或者System.identityHashCode(obj) 函数时,才生成hash值,保存在相应的hash位中。
- 上述代码第9行,第1次打印对象头,这时并没有调用hashCode()函数,并没有生成相应的值,
- 第11行调用了hashCode(),其值为:0x45456df1
- 第14行再次打印对象布局时,发现在对象头中已经保存了对应的值。
4.5 锁信息示例
/*
* This is another dive into the mark word.
*
* This one is the example of thin (displaced) lock. The data
* in mark word when lock is acquired is the reference to the
* displaced object header, allocated on stack. Once we leave
* the lock, the displaced header is discarded, and mark word
* is reverted to the default value.
*
* This example relies on biased locking not biasing the object
* at the first lock acquisition. Since JDKs up to 8 have biased
* locking startup delay, this example works out of the box there.
* On modern JDKs, starting with 9, this example should be run
* with with -XX:-UseBiasedLocking.
*/
@Test
public void thin_locking(){
class A { /* no fields */ }
final A a = new A();
ClassLayout layout = ClassLayout.parseInstance(a);
out.println(VM.current().details());
out.println("**** Fresh object");
out.println(layout.toPrintable());
synchronized (a) {
out.println("**** With the lock");
out.println(layout.toPrintable());
}
out.println("**** After the lock");
out.println(layout.toPrintable());
}
结果
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# 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]
**** Fresh object
com.example.sjjg.java.ObjectLayout$10A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 00 00 00 (00001101 00000000 00000000 00000000) (13)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 0a d6 02 20 (00001010 11010110 00000010 00100000) (537056778)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$10A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
**** With the lock
com.example.sjjg.java.ObjectLayout$10A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 98 01 b0 (00001101 10011000 00000001 10110000) (-1342072819)
4 4 (object header) ed 7f 00 00 (11101101 01111111 00000000 00000000) (32749)
8 4 (object header) 0a d6 02 20 (00001010 11010110 00000010 00100000) (537056778)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$10A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
**** After the lock
com.example.sjjg.java.ObjectLayout$10A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 98 01 b0 (00001101 10011000 00000001 10110000) (-1342072819)
4 4 (object header) ed 7f 00 00 (11101101 01111111 00000000 00000000) (32749)
8 4 (object header) 0a d6 02 20 (00001010 11010110 00000010 00100000) (537056778)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$10A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
4.6 对象age信息
volatile Object consumer;
@Test
public void gc_age(){
Object instance = new Object();
long lastAddr = VM.current().addressOf(instance);
ClassLayout layout = ClassLayout.parseInstance(instance);
for (int i = 0; i < 10_000; i++) {
long currentAddr = VM.current().addressOf(instance);
if (currentAddr != lastAddr) {
System.out.println(layout.toPrintable());
}
for (int j = 0; j < 10_000; j++) {
consumer = new Object();
}
lastAddr = currentAddr;
}
}
结果:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 11 00 00 00 (00010001 00000000 00000000 00000000) (17)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 19 00 00 00 (00011001 00000000 00000000 00000000) (25)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 21 00 00 00 (00100001 00000000 00000000 00000000) (33)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 29 00 00 00 (00101001 00000000 00000000 00000000) (41)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 31 00 00 00 (00110001 00000000 00000000 00000000) (49)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 39 00 00 00 (00111001 00000000 00000000 00000000) (57)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 41 00 00 00 (01000001 00000000 00000000 00000000) (65)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 49 00 00 00 (01001001 00000000 00000000 00000000) (73)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 51 00 00 00 (01010001 00000000 00000000 00000000) (81)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 59 00 00 00 (01011001 00000000 00000000 00000000) (89)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 61 00 00 00 (01100001 00000000 00000000 00000000) (97)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 02 00 20 (00000000 00000010 00000000 00100000) (536871424)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
注意结果中age位中值的变化
11 00 00 00 (00010001 00000000 00000000 00000000) (17)
^^^^
19 00 00 00 (00011001 00000000 00000000 00000000) (25)
^^^^
21 00 00 00 (00100001 00000000 00000000 00000000) (33)
^^^^
29 00 00 00 (00101001 00000000 00000000 00000000) (41)
^^^^
31 00 00 00 (00110001 00000000 00000000 00000000) (49)
^^^^
39 00 00 00 (00111001 00000000 00000000 00000000) (57)
^^^^
41 00 00 00 (01000001 00000000 00000000 00000000) (65)
^^^^
49 00 00 00 (01001001 00000000 00000000 00000000) (73)
^^^^
51 00 00 00 (01010001 00000000 00000000 00000000) (81)
^^^^
59 00 00 00 (01011001 00000000 00000000 00000000) (89)
^^^^
61 00 00 00 (01100001 00000000 00000000 00000000) (97)
^^^^
5. class word 信息
5.1 作用
一个指针,指向本类元数据,它里面保存类的信息:类名、基类、修饰符等。在64位机器上如果可压缩,那么为32位。
The klass
word in the object header points to the internal type metadata for the object. This word can be 64 bits, or if compressed, 32 bits.
5.2 示例
/*
* This is the example to have insight into object headers.
*
* In HotSpot, object header consists of two parts: mark word,
* and class word. We can clearly see the class word by analysing
* two empty instances of two distinct classes. See the difference
* in class word, that difference is the reference to class.
*/
@Test //10 ClassWord
public void class_word(){
class A { /* no fields */ }
class B { /* no fields */ }
out.println(VM.current().details());
out.println(ClassLayout.parseInstance(new A()).toPrintable());
out.println(ClassLayout.parseInstance(new A()).toPrintable());
out.println(ClassLayout.parseInstance(new B()).toPrintable());
}
结果:
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# 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.example.sjjg.java.ObjectLayout$7A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
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)
8 4 (object header) 15 63 03 20 (00010101 01100011 00000011 00100000) (537092885)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$7A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
com.example.sjjg.java.ObjectLayout$7A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
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)
8 4 (object header) 15 63 03 20 (00010101 01100011 00000011 00100000) (537092885)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$7A.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
com.example.sjjg.java.ObjectLayout$5B object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
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)
8 4 (object header) 90 65 03 20 (10010000 01100101 00000011 00100000) (537093520)
12 4 com.example.sjjg.java.ObjectLayout ObjectLayout$5B.this$0 (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
其中:
- 代码中new了两个A类对象,一个B类对象。
- 两个A对象指向相同的类元数据。
- A与B指向不同的类元数据。
5.3 注意事项:klass word 将被移除的草案
具体见:
https://openjdk.java.net/jeps/8198332
6.对象头中数组的长度
除了mark word 和 klass word 外,数组的对象头中还需要4个字节保存数组元素的个数。
/*
* The example for array length.
*
* Array length is not the part of array type, so VMs need another
* slot in header to store the array length. This can be demonstrated
* by this example.
*/
@Test //11
public void array_length(){
out.println(VM.current().details());
for (int c = 0; c < 8; c++) {
out.println("**** int[" + c + "]");
out.println(ClassLayout.parseInstance(new int[c]).toPrintable());
}
}
结果
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# 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]
**** int[0]
[I 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) 82 01 00 20 (10000010 00000001 00000000 00100000) (536871298)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 0 int [I.<elements> N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
**** int[1]
[I 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) 82 01 00 20 (10000010 00000001 00000000 00100000) (536871298)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 4 int [I.<elements> N/A
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
**** int[2]
[I 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) 82 01 00 20 (10000010 00000001 00000000 00100000) (536871298)
12 4 (object header) 02 00 00 00 (00000010 00000000 00000000 00000000) (2)
16 8 int [I.<elements> N/A
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
**** int[3]
[I 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) 82 01 00 20 (10000010 00000001 00000000 00100000) (536871298)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 int [I.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
其中的
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
12 4 (object header) 02 00 00 00 (00000010 00000000 00000000 00000000) (2)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
就是4个数组的长度。