(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对象详解的更多相关文章

  1. JVM 源码解读之 CMS 何时会进行 Full GC

    t点击上方"涤生的博客",关注我 转载请注明原创出处,谢谢!如果读完觉得有收获的话,欢迎点赞加关注. 前言 本文内容是基于 JDK 8 在文章 JVM 源码解读之 CMS GC 触 ...

  2. JVM源码分析之Java对象头实现

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Java对象头实现 HotSpot虚拟机中,对象在内存中的布局分为三 ...

  3. jvm源码解读--17 Java的wait()、notify()学习

    write and debug by 张艳涛 wait()和notify()的通常用法 A线程取得锁,执行wait(),释放锁; B线程取得锁,完成业务后执行notify(),再释放锁; B线程释放锁 ...

  4. object -c OOP , 源码组织 ,Foundation 框架 详解1

     object -c  OOP ,  源码组织  ,Foundation 框架 详解1 1.1 So what is OOP? OOP is a way of constructing softwar ...

  5. jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处

    之前分析的已经加载的.Class文件中都没有Static 静态变量,所以也就没这部分的解析,自己也是不懂hotspot 将静态变量放哪里去了,追踪源码之后,看清楚了整个套路,总体上来说,可以举例来说对 ...

  6. jvm源码解读--09 创建oop对象,将static静态变量放置在oop的96 offset处 第二篇

    先打断点systemDictionary.cpp 1915行 Universe::fixup_mirrors(CHECK); 进入 void Universe::fixup_mirrors(TRAPS ...

  7. jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

    粘贴源码 package com.test; import java.util.Random; public class Test { static int number=12; private in ...

  8. jvm源码解读--12 invokspecial指令的解读

    先看代码 package com.zyt.jvmbook; public class Girl extends Person{ public Girl() { int a; } @Override p ...

  9. jvm源码解读--11 ldc指令的解读

    写一个java文件 public static void main(String[] args) { String str1="abc"; String str2 ="a ...

随机推荐

  1. Go语言实现的23种设计模式之结构型模式

    摘要:本文主要聚焦在结构型模式(Structural Pattern)上,其主要思想是将多个对象组装成较大的结构,并同时保持结构的灵活和高效,从程序的结构上解决模块之间的耦合问题. 本文分享自华为云社 ...

  2. 管理后台Vue

    管理后台 遇到的问题 搭建 基于vue 3.0 Vue CLI 4.x Ant Design Vue 2.0 搭建后台管理系统 Ant Design Vue 2.0 npm i --save ant- ...

  3. .NET Core/.NET5/.NET6 开源项目汇总5:权限管理系统项目

    系列目录     [已更新最新开发文章,点击查看详细] 企业管理系统一般包含后台管理UI.组织机构管理.权限管理.日志.数据访问.表单.工作流等常用必备功能.下面收集的几款优秀开源的管理系统,值得大家 ...

  4. 学习JDK源码(一):String

    用了好久的Java了,从来没有看过jdk的源码,趁着今天有点时间,拿出了jdk的源码看了下,今天先看了关于String的,毕竟开发中String类型使用最广泛.在我们下载安装jdk的时候,部分源码也已 ...

  5. 入“坑”mybatis后如何挣脱?

    既然已经入"坑"mybatis了,你竟然还想着挣脱,我是不会让你挣脱的~ 当然我有一个算是挣脱的办法.那就是把它学会.理解透.这样我们也就不用在坑里一直徘徊,也算得上是一种挣脱吧! ...

  6. 温故知新Docker概念及Docker Desktop For Windows v3.1.0安装

    Docker 简介 什么是Docker? Docker是一个开放源代码软件项目,项目主要代码在2013年开源于GitHub.它是云服务技术上的一次创新,让应用程序布署在软件容器下的工作可以自动化进行, ...

  7. 三剑客-sed

    1.sed命令概述说明: 字符流编辑工具(行编辑工具) 2.sed命令作用说明: (1)擅长对行进行操作处理 (2)擅长将文件的信息进行修改调整/删除 3.sed具体功能 (1)文件中添加信息的能力( ...

  8. Git&Gitlab开发流程与运维管理

    Git&Gitlab开发流程与运维管理 作者 刘畅 时间 2020-10-31 实验系统版本centos7.5 主机名称 ip地址 配置 安装软件 controlnode 172.16.1.1 ...

  9. 基于Yarp实现内网http穿透

    Yarp介绍 YARP是微软开源的用来代理服务器的反向代理组件,可实现的功能类似于nginx. 基于YARP,开发者可以非常快速的开发一个性能不错的小nginx,用于代理http(s)请求到上游的ht ...

  10. AcWing 102. 最佳牛围栏

    农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头. 约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大 ...