java个对象头的mark word详情
Details about mark word of java object header
正在研究java对象头的构成
找到了一些文档和一些有趣的问题。
64位vm下,默认object head如下(因为UseCompressedOops
默认开启)
|------------------------------------------------ ---------------------------------------------- ----------|--------------------|
|对象头(96 位)|状态 |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
|标记字(64 位) |类字(32 位)| |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
| unused:25 | identity_hashcode:31 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |正常 |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
| thread:54 | epoch:2 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |有偏见 |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
| ptr_to_lock_record | lock:2 | OOP 到元数据对象 |轻量级锁定 |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
| ptr_to_heavyweight_monitor | lock:2 | OOP 到元数据对象 |重量级锁定 |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
| | lock:2 | OOP 到元数据对象 |标记为 GC |
|------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
如果UseCompressedOops
关闭,对象头是这样的:
|------------------------------------------------ ---------------------------------------------- ----------|--------------------|
|对象头(128 位)|状态 |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
|标记字(64 位) |类字(64 位)| |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |正常 |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
| thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |有偏见 |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
| ptr_to_lock_record:62 | lock:2 | OOP 到元数据对象 |轻量级锁定 |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
| ptr_to_heavyweight_monitor:62 | lock:2 | OOP 到元数据对象 |重量级锁定 |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
| | lock:2 | OOP 到元数据对象 |标记为 GC |
|------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
关于markword的C++源码在这里:
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp
我有一个问题:
为什么启用指针压缩后一位从未使用变为cms_free?
我怀疑它与 CMS 垃圾收集器有关,但我不知道它的作用。
而我查看对象头的相关信息时(包括上面两张表),大部分都提到了markOop.hpp
文件,而只引入了Lock 有关的。忽略cms_free, narrowOop, promo_bits, PromotedObjec markOop.hpp
那个重要的信息,所以对这部分很好奇
当使用平面指针时,由于对齐,地址指针的最低位始终为零,并且允许通过将 1 写入这些位来标记特殊状态。因此,当 CMS 想要表示特定的内存块(不再是对象)而是空闲内存时,它会将 klass
指针的最低位设置为 1。
但压缩指针功能利用相同的 属性 通过右移地址并不留下未使用的低位通过 32 位指针寻址更多内存。因此,CMS 必须将此位存储在其他地方,即有问题的 cms_free_bit
。
来源:concurrentMarkSweepGeneration.cpp:
// A block of storage in the CMS generation is always in
// one of three states. A free block (FREE), an allocated
// object (OBJECT) whose size() method reports the correct size,
// and an intermediate state (TRANSIENT) in which its size cannot
// be accurately determined.
// STATE IDENTIFICATION: (32 bit and 64 bit w/o COOPS)
// -----------------------------------------------------
// FREE: klass_word & 1 == 1; mark_word holds block size
//
// OBJECT: klass_word installed; klass_word != 0 && klass_word & 1 == 0;
// obj->size() computes correct size
//
// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
//
// STATE IDENTIFICATION: (64 bit+COOPS)
// ------------------------------------
// FREE: mark_word & CMS_FREE_BIT == 1; mark_word & ~CMS_FREE_BIT gives block_size
//
// OBJECT: klass_word installed; klass_word != 0;
// obj->size() computes correct size
//
// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
正在研究java对象头的构成
找到了一些文档和一些有趣的问题。
64位vm下,默认object head如下(因为UseCompressedOops
默认开启)
|------------------------------------------------ ---------------------------------------------- ----------|--------------------| |对象头(96 位)|状态 | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| |标记字(64 位) |类字(32 位)| | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| | unused:25 | identity_hashcode:31 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |正常 | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| | thread:54 | epoch:2 | cms_free:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |有偏见 | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| | ptr_to_lock_record | lock:2 | OOP 到元数据对象 |轻量级锁定 | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| | ptr_to_heavyweight_monitor | lock:2 | OOP 到元数据对象 |重量级锁定 | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------| | | lock:2 | OOP 到元数据对象 |标记为 GC | |------------------------------------------------ ------------------------------|---------------- ----------|--------------------|
如果UseCompressedOops
关闭,对象头是这样的:
|------------------------------------------------ ---------------------------------------------- ----------|--------------------| |对象头(128 位)|状态 | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| |标记字(64 位) |类字(64 位)| | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| | unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |正常 | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP 到元数据对象 |有偏见 | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| | ptr_to_lock_record:62 | lock:2 | OOP 到元数据对象 |轻量级锁定 | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| | ptr_to_heavyweight_monitor:62 | lock:2 | OOP 到元数据对象 |重量级锁定 | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------| | | lock:2 | OOP 到元数据对象 |标记为 GC | |------------------------------------------------ --------------------------|-------------------- ----------|--------------------|
关于markword的C++源码在这里: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp
我有一个问题:
为什么启用指针压缩后一位从未使用变为cms_free?
我怀疑它与 CMS 垃圾收集器有关,但我不知道它的作用。
而我查看对象头的相关信息时(包括上面两张表),大部分都提到了markOop.hpp
文件,而只引入了Lock 有关的。忽略cms_free, narrowOop, promo_bits, PromotedObjec markOop.hpp
那个重要的信息,所以对这部分很好奇
当使用平面指针时,由于对齐,地址指针的最低位始终为零,并且允许通过将 1 写入这些位来标记特殊状态。因此,当 CMS 想要表示特定的内存块(不再是对象)而是空闲内存时,它会将 klass
指针的最低位设置为 1。
但压缩指针功能利用相同的 属性 通过右移地址并不留下未使用的低位通过 32 位指针寻址更多内存。因此,CMS 必须将此位存储在其他地方,即有问题的 cms_free_bit
。
来源:concurrentMarkSweepGeneration.cpp:
// A block of storage in the CMS generation is always in // one of three states. A free block (FREE), an allocated // object (OBJECT) whose size() method reports the correct size, // and an intermediate state (TRANSIENT) in which its size cannot // be accurately determined. // STATE IDENTIFICATION: (32 bit and 64 bit w/o COOPS) // ----------------------------------------------------- // FREE: klass_word & 1 == 1; mark_word holds block size // // OBJECT: klass_word installed; klass_word != 0 && klass_word & 1 == 0; // obj->size() computes correct size // // TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT // // STATE IDENTIFICATION: (64 bit+COOPS) // ------------------------------------ // FREE: mark_word & CMS_FREE_BIT == 1; mark_word & ~CMS_FREE_BIT gives block_size // // OBJECT: klass_word installed; klass_word != 0; // obj->size() computes correct size // // TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT