JVM对象头的简单记录

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:用于保存偏向时间戳
  • 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 
    
发布了128 篇原创文章 · 获赞 45 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/alionsss/article/details/103676183