一、引言
-
java对象头很重要,synchronize、GC、HashCode、biasedLock、ObjectMonitor都是在对象头上作文章。php
-
其实整个Java能够说是构建在oop-klass体系上的,相信从各类技术博客、书籍你们都了解很多。可是基本上都是32位虚拟机下,可能周志明大神的学习笔记太多。java
-
本文不打算讲讲oop-klass体系(能力有限),只聊聊64位虚拟机下普通的对象头,jdk1.8.0_221,jvm参数:-XX:-UseCompressedOops,但愿对读者有所帮助。数组
二、认识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.一、 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,不管是包装类型仍是基本类型。
- 🌰来了。
- 可见普通类型的对象也被安排一个object header。
2.三、arrayOopDesc
- objArrayOopDesc、typeArrayOopDesc继承自arrayOopDesc,其中包装类型的数组类型是objArrayOopDesc,基本类型数组是typeArrayOopDesc。
- 上文提到了oop的属性,其中arrayOopDesc有点特殊,它不只有markword、klass,还有个length属性来记录数组长度。可是翻看jdk源码,arrayOopDesc除了继承自arrayOopDesc,也没有扩展任何属性,那length属性怎么来的呢?其实这个length属性属于对象头的一部分,它不是以一个独立属性的形式存在,而是在对象头markword和klass以后固定的位置存储的一个值。
- 下面简单示意能够看出,64位虚拟机下,length出如今offset=16的位置。其中三、4等于数组长度毫不是偶然的,读者能够自行验证。
- 注意:对象头与实例数据无关,其实arrayOopDesc的length属于对象头,不属于data的一部分。
2.四、markword
- markword是oop的一部分,其中hashcode、GC、轻量级锁/重量级锁/偏向锁、分代年龄都是在markword上作文章。markword起始于对象头offset=0的位置,在64位虚拟机上占8个字节。
- 上面这张图你们都见过不少次了,从名称中也能够看出我上面一点所言不虚。那么问题来了,不少人一眼看出你这篇文章上面8个字段64个bit好像除了一个看到个1,你没有锁标志我能理解,hashcode你也吃了吗?你随便写几个对象hashcode都是0吗?
- 最开始我也诧异我骨骼惊奇(感受能够人脑挖矿、手算md5了),开个玩笑。。。java这么容易hash膨胀,我要不要转行php?骚年,是你书读的太少啊。🌰来了。
三、小结
- 主要介绍了java对象头oop,包括实例对象头、数组对象头。
- 对对象头中的markword结合demo进行简单说明,抛砖引玉。至于偏向锁、轻量级锁、重量级锁升级过程的markword的变化待后续可能有详尽篇幅。不过都是在java对象头中作文章,读者能够结合锁升级流程图自行验证。