Details about mark word of java object header
Asked Answered
B

1

6

I am studying the composition of java object header.

Found some documents and some interesting problems.

Under 64 bit vm, the default object head is as follows (Because UseCompressedOops is on by default)

|--------------------------------------------------------------------------------------------------------------|--------------------|
|                                            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   |
|--------------------------------------------------------------------------------|-----------------------------|--------------------|

If UseCompressedOops is turned off, the object header looks like this:

|------------------------------------------------------------------------------------------------------------|--------------------|
|                                            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   |
|------------------------------------------------------------------------------|-----------------------------|--------------------|

And the C++ source code about markword is here: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp

I have a question:

Why one bit has changed from unused to cms_free when pointer compression is enabled?

I suspect it has something to do with the CMS garbage collector, but I don't know what it does.

And when I check the relevant information of the object header (including the two tables above), most of them mentioned the markOop.hpp file, but only introduced the Lock related. Ignore the cms_free, narrowOop, promo_bits, PromotedObjec mentioned in markOop.hpp that important information, so I am curious about this part.

Brasca answered 2/4, 2020 at 6:55 Comment(2)
I don't know how CMS used to use object headers but CMS has been deprecated for a long time and removed in JDK 14: openjdk.java.net/jeps/363. As such, I wouldn't bother about this and suggest studying a more modern Hotspot implementation.Tipstaff
@Juraj Martinka Thank you for your prompt. I read the markoop.hpp code of jdk11, but it has not changed. In jdk14, I found markword.hpp, but no markoop.hpp. There is no CMS related description in the comments. Before there is any better answer, I can only think of cms_free as a special treatment for CMS collectorBrasca
E
8

When using flat pointers, the lowest bits of address pointers are always zero due to alignment and allow marking special state by writing ones into these bits. So the CMS set the lowest bit of the klass pointer to one when it wants to denote that the particular chunk of memory is not an object (anymore), but free memory.

But the compressed pointer feature utilizes the same property to address more memory via a 32 bit pointer by right shifting the address and leaving no unused lower bits. Therefore, the CMS has to store this bit somewhere else, i.e. the cms_free_bit in question.

Source: 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
Ermin answered 6/4, 2020 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.