JVM对象头的简单记录
对象头示意图
-
对象结构总览
结构 描述 header 对象头 instance data 实例信息 padding 对齐信息 - JVM要求对象的大小为8bit的倍数,padding用于补齐数据,所以可能有可能没有
- 对齐8bit(1byte)的原因:为了实现的简单与高效。一个class的每个field都会分配“byte offset”,再对每个单独的byte的进行读/写访问。如果不对齐byte,则要记录“sub-byte offsets”,会导致额外的访问逻辑。直接按byte访问则更简单、高效。
-
对象头(32位)
32bits 32bits 32bits Mark Word Klass Word array length - 如果不是数组,则没有array length信息
-
Mark Word 结构图 (32位)
25bits
4bits
1bits
2bits
锁状态
23bits
2bits
是否偏向锁
锁标志位
HashCode
分代年龄
0
01
无锁
Thread ID
Epoch
分代年龄
1
01
偏向锁
指向栈中锁记录的指针
00
轻量级锁
指向重量级锁的指针
10
重量级锁
空
11
GC标记
- 64位时或启用COOPs时,会有所不同,具体请查看后面附的“对象头描述源码”
对象头信息描述
- Mark Word
- 锁标志位:用于JVM判定对象是否被锁住,以及锁膨胀优化。包括
- 无锁:新建一个对象的默认状态
- 偏向锁:只需比较 Thread ID,适用于单个线程重入
- 轻量级锁:CAS自旋,速度快,但存在CPU空转问题
- 重量级锁:需调用系统级互斥锁(mutex/monitor),效率低
- GC标记:由markSweep使用,标记一个对象为无效状态
- 分代年龄:即在young区存活的次数,默认达到15次后进入old区,4bits最大值为15(32位/64位一样)
- HashCode:调用 System.identityHashCode(…) 获得,HotSpot使用xor-shift算法
- Thread ID:偏向锁偏向的线程id
- Epoch:用于保存偏向时间戳
- 锁标志位:用于JVM判定对象是否被锁住,以及锁膨胀优化。包括
- Klass Word:即class指针(指向内存中对象的class类,例如通过getClass拿到类信息)
- 数组长度:64位进程中占用64bits(8字节)的空间,只有当对象是一个数组对象时才会有这部分(这就解释了为什么数组对象的最大长度小于int最大值(32位:Integer.MAX_VALUE - 3;64位:Integer.MAX_VALUE - 2))
附:对象头描述(OpenJDK JVM源码)
- oop.hpp
// oopDesc is the top baseclass for objects classes. The {name}Desc classes describe // the format of Java objects so the fields can be accessed from C++. // oopDesc is abstract. ...省略... class oopDesc { friend class VMStructs; private: volatile markOop _mark; union _metadata { Klass* _klass; narrowKlass _compressed_klass; } _metadata; ...省略... }
- markOop.hpp
// 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 // // We assume that stack/thread pointers have the lowest two bits cleared.
附:数组最大长度的判定(OpenJDK JVM源码)
- arrayKlass.cpp
objArrayOop arrayKlass::allocate_arrayArray(int n, int length, TRAPS) { if (length < 0) { THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); } if (length > arrayOopDesc::max_array_length(T_ARRAY)) { report_java_out_of_memory("Requested array size exceeds VM limit"); JvmtiExport::post_array_size_exhausted(); THROW_OOP_0(Universe::out_of_memory_error_array_size()); } // ...... }
- arrayOop.hpp
// Return the maximum length of an array of BasicType. The length can passed // to typeArrayOop::object_size(scale, length, header_size) without causing an // overflow. We also need to make sure that this will not overflow a size_t on // 32 bit platforms when we convert it to a byte size. static int32_t max_array_length(BasicType type) { assert(type >= 0 && type < T_CONFLICT, "wrong type"); assert(type2aelembytes(type) != 0, "wrong type"); const size_t max_element_words_per_size_t = align_size_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment); const size_t max_elements_per_size_t = HeapWordSize * max_element_words_per_size_t / type2aelembytes(type); if ((size_t)max_jint < max_elements_per_size_t) { // It should be ok to return max_jint here, but parts of the code // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for // passing around the size (in words) of an object. So, we need to avoid // overflowing an int when we add the header. See CRs 4718400 and 7110613. return align_size_down(max_jint - header_size(type), MinObjAlignment); } return (int32_t)max_elements_per_size_t; }
- sizecalc.h (32位系统 size_t=4字节,64位系统 size_t=8字节,当然你也可以开启压缩设置-XX:+UseCompressedOops)
#include <stdint.h> /* SIZE_MAX for C99+ */ /* http://stackoverflow.com/questions/3472311/what-is-a-portable-method-to-find-the-maximum-value-of-size-t */ #ifndef SIZE_MAX #define SIZE_MAX ((size_t)-1) #endif