一个Java对象在JVM中是由一个对应角色的oop
对象来描述的,
比如instanceOopDesc
用来描述普通实例对象,arrayOopDesc
用来描述数组对象,而这些类型的oop对象均是继承自oopDesc
。
class oopDesc {
friend class VMStructs;
friend class JVMCIVMStructs;
private:
// 对象头
volatile markOop _mark;
// 元数据
union _metadata {
// 对应的Klass对象
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
oopDesc主要包含两部分,一部分是_mark
,一部分是_metadata
,
_mark
_mark是一个markOop
实例,它描述了一个对象的头信息,用于存储对象的运行时记录信息,如哈希值、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等:
源码位置: hostspot/share/oops/markOop.hpp (jdk10)
_metadata
包含一个普通_klass
和一个压缩后的_compressed_klass
,详细信息参见OpenJDK Wiki。
markOop描述了对象的头部信息。
注意标记不是真正的oop而是一个单词。
由于历史原因,它被放置在oop层次结构中。
对象头的位格式:
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)
问题: Java对象如何存储?
对象的实例(instantOopDesc)保存在堆上,对象的元数据(instantKlass)保存在方法区(元空间?),对象的引用保存在栈上。
hash: 保存对象的哈希码
age: 保存对象的分代年龄
biased_lock: 偏向锁标识位
lock: 锁状态标识位
JavaThread:* 保存持有偏向锁的线程ID
epoch: 保存偏向时间戳markOop中不同的锁标识位,代表着不同的锁状态: