两种说法中对象头涵盖的内容不同,前者所指的Object Header仅仅指的是markOop指针的大小——在32位机器上指针的大小是32bit(4Bytes),在64位机器上指针的大小是64bit(8Bytes);而后者除了markOop指针之外,还包含了Klass*这一个类型元数据,用于描述Heap对象在Metaspace中的实际类型,那么在不考虑启用压缩指针: -XX:+UseCompressedOops的情况下,加上这个Klass*指针的大小,Object Header在32位VM里占64bit内存空间,在64位VM里占128位内存空间的结论。在启用压缩指针之后,64位VM的Klass*指针会被压缩成narrowKlass -> unsigned int类型的大小——变成了32bit,因为是union类型,所以_metadata还是占用了64bit的内存空间,多出来的32bit空间就空着了——后面会讲到它的用处。我更倾向于将普通对象的对象头定义为【markOop + Klass*】的组合,所以后者的结论可能更合适。
基于此,在HotSpot VM中,普通对象的对象头是这么定义的:
volatile markOop _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
对于数组这种特殊的对象,它的对象头中又增加了一个length用于描述数组的大小,在HotSpot VM中如果启用压缩指针的话,它其实是占用的_metadata空出来的后面的4个字节的内存空间,因此这种情况下128bit的内容空间就能表示一个数组的对象头了;如果没有启用指针压缩 -XX:-UseCompressedOops呢?它会追加到内嵌的实例数据的最后,这时候考虑到字节对齐,我们无法给出确切的大小了。
// The layout of array Oops is:
//
// markOop
// Klass* // 32 bits if compressed but declared 64 in LP64.
// length // shares klass memory or allocated after declared fields.
markOop用于存储对象在runtime是的有用信息,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳、转发指针等等。VM使用这些紧凑的bitMap描述对象在同步过程或GC过程中的的必要信息,辅助VM Runtime实现对象的同步机制和垃圾回收的功能——虽然看到R大有时候吐槽这玩意儿尤其是RT的同步机制开销很大~
回到题主的问题,对象头中是否存储了类型的地址信息——答案见上面,这就是所谓的Klass*。至于JavaThread*线程所有者的指针大小,请看下面的注释——在HotSpot VM中 Thread在new的时候已经采用了一定的算法,将它的指针大小控制在了譬如32位VM下仅占用23bit的内存空间——所以,请放心,放得下。
// The markOop describes the header of an object.
//
// Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// 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)
// 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)
//
// - 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), and for the CMS "freeness" bit in the 64bVM (+COOPs).
//
// [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 by markSweep to mark an object
// not valid at any other time
//