转载

Java 对象头

  • java对象头很重要,synchronize、GC、HashCode、biasedLock、ObjectMonitor都是在对象头上做文章。

  • 其实整个Java可以说是构建在oop-klass体系上的,相信从各种技术博客、书籍大家都了解不少。但是基本上都是32位虚拟机下,可能周志明大神的学习笔记太多。

  • 本文不打算讲讲oop-klass体系(能力有限),只聊聊64位虚拟机下普通的对象头,jdk1.8.0_221,jvm参数:-XX:-UseCompressedOops,希望对读者有所帮助。

2、认识oop

  • oo-klass的基石之一,先来看看oop(其实是个oopDesc *)
typedef class oopDesc*                            oop;

class oopDesc{
    friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;
}
复制代码

2.1、 oop的继承体系

  • 取自jdk8,从源码可以看出xxOop是xxxOopDesc*的别名。
typedef class oopDesc*                            oop;
typedef class   instanceOopDesc*            instanceOop;
typedef class   arrayOopDesc*                    arrayOop;
typedef class     objArrayOopDesc*            objArrayOop;
typedef class     typeArrayOopDesc*            typeArrayOop;
复制代码
  • 主要是instanceOopDesc和arrayOopDesc。均继承自oopDesc,没有扩充字段属性,下文不在赘述。也就是说instanceOopDesc、arrayOopDesc的markword、klass属性均来自oopDesc,关于arrayOopDesc稍微有点特殊,下文详述。

2.2 、InstanceOopDesc

  • 普通的Java对象均是instanceOopDesc,无论是包装类型还是基本类型。
  • :chestnut:来了。
Java 对象头
  • 可见普通类型的对象也被安排一个object header。

2.3、arrayOopDesc

  • objArrayOopDesc、typeArrayOopDesc继承自arrayOopDesc,其中包装类型的数组类型是objArrayOopDesc,基本类型数组是typeArrayOopDesc。
Java 对象头
  • 上文提到了oop的属性,其中arrayOopDesc有点特殊,它不仅有markword、klass,还有个length属性来记录数组长度。但是翻看jdk源码,arrayOopDesc除了继承自arrayOopDesc,也没有扩展任何属性,那length属性怎么来的呢?其实这个length属性属于对象头的一部分,它不是以一个独立属性的形式存在,而是在对象头markword和klass之后固定的位置存储的一个值。
  • 下面简单示意可以看出,64位虚拟机下,length出现在offset=16的位置。其中3、4等于数组长度绝不是偶然的,读者可以自行验证。
Java 对象头
  • 注意:对象头与实例数据无关,其实arrayOopDesc的length属于对象头,不属于data的一部分。
Java 对象头

2.4、markword

  • markword是oop的一部分,其中hashcode、GC、轻量级锁/重量级锁/偏向锁、分代年龄都是在markword上做文章。markword起始于对象头offset=0的位置,在64位虚拟机上占8个字节。
Java 对象头
  • 上面这张图大家都见过很多次了,从名称中也可以看出我上面一点所言不虚。那么问题来了,很多人一眼看出你这篇文章上面8个字段64个bit好像除了一个看到个1,你没有锁标志我能理解,hashcode你也吃了吗?你随便写几个对象hashcode都是0吗?
  • 最开始我也诧异我骨骼惊奇(感觉可以人脑挖矿、手算md5了),开个玩笑。。。java这么容易hash膨胀,我要不要转行php?骚年,是你书读的太少啊。:chestnut:来了。
Java 对象头
  • 仔细看图,相信你就明白了。注意markword=00000008807e2501,其中unused25位,hashcode与integers1.hashcode()相等,2个标志位也ok。

  • 再看一个偏向锁状态的(标志位101)

Java 对象头

3、小结

  • 主要介绍了java对象头oop,包括实例对象头、数组对象头。
  • 对对象头中的markword结合demo进行简单说明,抛砖引玉。至于偏向锁、轻量级锁、重量级锁升级过程的markword的变化待后续可能有详尽篇幅。不过都是在java对象头中做文章,读者可以结合锁升级流程图自行验证。
原文  https://juejin.im/post/5e0a92c0f265da33e763dd95
正文到此结束
Loading...