(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,变为二进制
1110000 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值是一样的