jvm源码解读--15 oop对象详解
Posted 张三f
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm源码解读--15 oop对象详解相关的知识,希望对你有一定的参考价值。
(gdb) p obj $15 = (oopDesc *) 0xf3885d08 (gdb) p * obj $16 = { _mark = 0x70dea4e01, _metadata = { _klass = 0x2000070e, _compressed_klass = 536872718 }, static _bs = 0x7f658801eea8 }
1.介绍oo对象
现在先看最长使用的oop对象的定义,jvm的二分模型就是oop和class,所有的对象在hotspot层全被具体化成了oop对象,
oop的结构很简单,表示一个hotspot对象,也可以理解为一个java对象(不过包了一层handle才是java对象), 比如在java中创建一个对象
Student xm=new Student();
xm.name="小明";
xm.age=18;
这个xm就是oop,,这个oop被放在堆中,代表的就是xm这个对象,那么这个对象有成员变量name,age,那么oop对象在内存中的
oop对象 | |
内存地址64位 | _mark属性 |
内存地址32(压缩指针)或64 | _metadata,指向class对象 |
内存地址 | "小明"oop对象指针 |
内存地址 | 18,int类型数值 |
那么整个对象的大小包括了oop对象头大小为12字节(压缩)+成员变量1+成员变量2..,其中包括父类的成员变量的值,不包括static变量的值(static变量保存在class的java_mirror属性中)
如果新建一个oop对象,分配内存需要计算oop大小,那么oop的size()实际上是取值oop对应的元对象class的_layout_helper 的大小
贴一个class对象
(gdb) p k $87 = (InstanceKlass *) 0x100060030 (gdb) p * k $88 = (InstanceKlass) { <Klass> = { <Metadata> = { <MetaspaceObj> = {<No data fields>}, members of Metadata: _vptr.Metadata = 0x7f5aa945e590 <vtable for InstanceKlass+16>, _valid = 0 }, members of Klass: _layout_helper = 24, _super_check_offset = 56, _name = 0x7f5aa014b5d8, _secondary_super_cache = 0x0, _secondary_supers = 0x7f5aa5399090, _primary_supers = {0x100000f30, 0x100060030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, _java_mirror = 0xd758fc70, _super = 0x100000f30, _subklass = 0x0, _next_sibling = 0x1000471a8, _next_link = 0x0, _class_loader_data = 0x7f5aa0153768, _modifier_flags = 1, _access_flags = { _flags = 2097185 }, _last_biased_lock_bulk_revocation_time = 0, _prototype_header = 0x5, _biased_lock_revocation_count = 0, _modified_oops = 1 \'\\001\', _accumulated_modified_oops = 0 \'\\000\' }, members of InstanceKlass: static _total_instanceKlass_count = 415, _annotations = 0x0, _array_klasses = 0x0, _constants = 0x7f5aa5799080, _inner_classes = 0x7f5aa5399060, _source_debug_extension = 0x0, _array_name = 0x0, _nonstatic_field_size = 2, _static_field_size = 1, _generic_signature_index = 0, _source_file_name_index = 69, _static_oop_field_count = 0, _java_fields_count = 3, _nonstatic_oop_map_size = 1, _is_marked_dependent = false, _misc_flags = 6, _minor_version = 0, _major_version = 51, _init_thread = 0x0, _vtable_len = 5, _itable_len = 2, _oop_map_cache = 0x0, _member_names = 0x0, _jni_ids = 0x0, _methods_jmethod_ids = 0x0, _dependencies = 0x0, _osr_nmethods_head = 0x0, _breakpoints = 0x0, _previous_versions = 0x0, _cached_class_file = 0x0, _idnum_allocated_count = 3, _init_state = 1 \'\\001\', _reference_type = 0 \'\\000\', _jvmti_cached_class_field_map = 0x0, _verify_count = 0, _methods = 0x7f5aa5799338, _default_methods = 0x0, _local_interfaces = 0x7f5aa5399090, _transitive_interfaces = 0x7f5aa5399090, _method_ordering = 0x7f5aa5399048, _default_vtable_indices = 0x0, _fields = 0x7f5aa5799308 }
这个类为
(gdb) p name->as_utf8() $80 = 0x7f5aa0009c88 "com/test/Test"
2.介绍mark成员变量
这里先贴出来注释的东西
// 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.
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
unused:25 | hash:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |
哈希值 | gc存活年度 | 偏向锁 | 状态 | ||
111 0000 1101 1110 1010 0100 1110 (70D EA4E) |
0 | 000 0 | 0 | 01 |
_mark = 0x70dea4e01,变为二进制
111 0000 1101 1110 1010 0100 1110 0000 0001
对于lock:2的取值不同,代表的意义不同,当为01的时候,不锁,那么按照上表表头来解析,如果是11,那么是在gc的时候会将已经已经复制到to区域的oop的,在没有清除之前,他会在eden区域,这个时候会将eden区域的老oop对象后两位设置为11; (used by markSweep to mark an object not valid at any other time)
// [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
那么现在,现在执行new Object().hasCode()方法就是,取得oop的hash值的执行过程为
JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) JVMWrapper("JVM_IHashCode"); // as implemented in the classic virtual machine; return 0 if object is NULL return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ; JVM_END
进入
intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) { if (UseBiasedLocking) { // thread-local storage. if (obj->mark()->has_bias_pattern()) { // Box and unbox the raw reference just in case we cause a STW safepoint. Handle hobj (Self, obj) ; // Relaxing assertion for bug 6320749. assert (Universe::verify_in_progress() || !SafepointSynchronize::is_at_safepoint(), "biases should not be seen by VM thread here"); BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current()); obj = hobj() ; assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } } ObjectMonitor* monitor = NULL; markOop temp, test; intptr_t hash; markOop mark = ReadStableMark (obj); // object should remain ineligible for biased locking assert (!mark->has_bias_pattern(), "invariant") ; if (mark->is_neutral()) { hash = mark->hash(); // this is a normal header if (hash) { // if it has hash, just return it return hash; } hash = get_next_hash(Self, obj); // allocate a new hash code temp = mark->copy_set_hash(hash); // merge the hash code into header // use (machine word version) atomic operation to install the hash test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark); if (test == mark) { return hash; }
接着
// hash operations intptr_t hash() const { return mask_bits(value() >> hash_shift, hash_mask); }
看 (gdb) p/d hash_shift $18 = 8
那么 uintptr_t value() const { return (uintptr_t) this; } 那么就是将0x70dea4e01,右移8位
在看掩码
(gdb) p/x hash_mask $20 = 7FFF FFFF
二进制位01111111111111111111111111111111,那么31位1,就和hash的31为对应上了
那么打印一下计算结果
(gdb) p/x hash $22 = 0x70dea4e
所以:这个值和(70D EA4E) 表格中的hash值是一样的
以上是关于jvm源码解读--15 oop对象详解的主要内容,如果未能解决你的问题,请参考以下文章