若是你已经知道什么是Mark Word,那我也但愿你都好好阅读下本篇文章,由于你有可能发现不同的切入点来帮助你更加深刻的了解Mark Word,这对你来讲是个很好的巩固所学知识的机会,同时也是一场技术交流,一个有逼格的程序员应该不会错过这样的机会吧!
java
若是你还不知道什么是Mark Word,那你更要好好阅读本篇文章了,由于Mark Word不只是一个可让你用来装X的词汇,实际上它是一个很是重要的概念,很是重要的知识点,对你学习Java中的各类锁是很是有必要的,也能够说是必须的,而为何要阅读本篇文章嘞?
程序员
由于,庆哥的文章,接地气啊,通俗易懂,那咱就一块儿搞起吧!面试
Mark Word是啥?翻译过来就是对象标记,先经过代码让你直观看下Mark Word究竟是个什么东东,来看下面代码:编程
class OneClass{ }
这是啥?一个很是很是简单的类,啥也没有,就是声明了一个类对吧,好,看接下来的操做:安全
public static void main(String[] args) { System.out.println(ClassLayout.parseInstance(new OneClass()).toPrintable()); }
这是啥?先来看看打印出来的是些个啥?
看得懂吗?红框中的就是对象标记Mark Word了,那今天这篇文章的目的就是让你读懂上面这张图究竟是个啥?以及有哪些重要的信息!
markdown
事先声明,今天的文章,干货比较多,看起来有点费劲,请先作好准备!
并发
开干!
jvm
什么是对象实例呢?说的简单点,咱们new出来的东西就是一个对象实例,也就是日常说的什么实例化,就是你建立出来的那个在堆里面的实例对象,ok,这个概念相信你们都懂,不赘述,接下来你就有可能不知道了,你说对于一个对象实例,它有哪几部分组成呢?
maven
这些都是啥?这里咱们能够类比下咱们的人,一个对象实例就比如是一个完整的人,拿你本身来类比就行,这里咱们拿你本身来类比,这个对象头就是你的大脑啦,而后实例数据就比如的身体,而对齐填充就比如你的脚,画个图大概就是这样的:
这里可能这个对齐填充你们不是很好理解,什么意思呢?就好比说你要参加一个面试,可是人家硬性要求一米八,可是你就是一米七八,咋办,鞋垫子拯救你啊,懂我意思吧。 那这个对齐填充也是这么回事,对齐填充要求一个对象实例的大小必须是8个字节的倍数,那你不够了的话,对齐填充起做用给你整到8字节的倍数,懂了吧!ide
如今咱们知道了,一个对象实例包括对象头,实例数据和对齐填充,其实更详细的还有以下划分,看图:
什么意思呢?就是你得知道这么一回事,对于对象头来讲,它是分为两部分的,一是对象标记,也就是今天要注重说的Mark Word,还有一个就是Class Pointer类型指针了,我们的重点是Mark Word!
这里先给你们简单说说什么是实例数据,帮助你们有个直观的认识!
什么叫作实例数据呢?写一个简单的代码来举例说明:
咱们这里定义了一个超级简单的Person类,里面啥也没有,这个时候咱们去实例化一个Person对象,也就是这样:
这个时候你知道咱们这个对象有多大吗?实际上目前它就占16个字节,也就是对象头中的Mark Word和类型指针,说白了就是,你刚开始建立一个空荡荡的Java对象,起初里面是只有对象头的,也就是组成对象头的对象标记Mark Word占8个字节,类型指针占8个字节(存在指针压缩的话就只有4个字节,会对齐填充4个字节),一共16个字节,若是这个时候咱们再添加一点代码,好比这样:
咱们给Person类增长了一个属性,咱们知道int占四个字节,加上对象头的16个字节,此时一共20个字节,可是一个对象的大小要是8字节的倍数,那目前20字节,因此须要到24字节才符合条件,此时就须要对齐填充4个字节,最终凑成24个字节,这个Person类中的一些东西(好比这里定义的int)就是实例数据了,另外想必这下你也更清楚什么是对齐填充了吧!
ok,到了这里,什么是实例数据,什么是对齐填充,是否是比较清晰了?固然若是你目前理解的还不是很透彻也不要紧,只有一个大体知道是怎么回事就ok啦!
这是个啥意思呢?咱们来看,好比咱们建立一个Person对象,咱们通常怎么写,是否是这样:
Person p = new Person()
别看这一行简单的代码,你得分清楚几个概念了,首先就是new person(),这个你们最熟悉,就是建立一个新的对象,在哪,是在堆中建立吧,而后就是这个p了,它是啥,这个是对象引用,存储在哪,知道吧,这个是在栈内存,那么这个Person呢?是否是不少人就不太清楚了呢?
记住了,这个Person能够理解成一个模板,就比如人类,而后后面new Person()生产出具体的某我的,而这个Person就是个生产出这我的的模具,最重要的要知道,这个Person存在哪里,它是在方法区的,结合上面说的对象标记,来看一张图:
必定要注意这个Person的位置在哪里!它是存在方法区的,这个是java虚拟机的知识了,先做简单了解便可!
而这里的类型指针,就是指向这个Person类的指针了!那么关于什么是类型指针,你是否也有一个简单的认识了?再也不是一个陌生的词汇了吧!
这就ok啦,我们继续,重难点还在后面嘞!
对于一个Java对象来讲,对象头是极其重要的,对象头主要有对象标记和类型指针两部分组成,接下来须要重点看下对象标记,也就是Mark Word,下面是针对64位JVM(那也就是说还有32位的,考虑到如今基本都是64的了,32的直接pass掉)的Mark Word来讲的,它的组成是这样的:
第一次看到这张图会以为比较懵,没事,很正常,我刚开始学习也是这样,别着急,通过下面的一步步的分析,你就会清晰不少!首先记住,上图表示的就是一个Mark Word的内部是啥样的!咱们以前不是说了嘛,对象标记Mark Word是占8字节的,那也就是64bit,那这64bit都是存储的啥,上面这种图就给出了答案,你看这里:
一个Mark Word就是8字节64位,里面存储了啥,就得看上面这张图,有内味儿了吧,上面这张图是否是稍微熟悉了一点点,那如今你应该知道这么些东西:
一个Java对象由对象头,实例数据和对齐填充组成,其中对象头是极其重要的,对象头是由对象标记Mark Word和类型指针组成,其中又以Mark Word最重要,对于Mark Word它占8个字节也就是64位!
ok,以上内容都清楚吧!那咱就继续!
接下来咱就以锁这个切入点去详细的看看这个Mark Word!
咱们都知道在并发状况下也就是要解决线程安全的话要加锁,其实这个加锁就是对对象加锁,那如何去判断或者说知道这个对象加锁了没有或者加的什么锁,这些个信息其实就保存在对象头中的Mark Word中,上面这张图就是关于一个Mark Word的具体结构,能够看出,一个Java对象其实在不一样的状态下,它是不同的,主要是有不一样的锁,好比没有锁,轻量级锁,还有什么偏向锁,重量级锁等等,不一样的锁,在Mark Word中就会有不一样的状态标记。
只看这些,实际上是比较晦涩难懂的,接下来须要结合代码来看下:
这就是一个空类,啥也没有,要怎么看这个对象标记Mark Word呢?这里咱们须要加入一个依赖,也就是你的Java项目是个maven项目,能够引入pom依赖,而后添加如下依赖:
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.10</version> </dependency>
这个依赖是干吗的呢?这是一个代码工具叫作JOL,也就是Java Object Layout,主要就是用来分析java虚拟机中的对象布局的,也就是在java对象在虚拟机中的大小和分布,ok,接下来加入上述这个依赖以后咱们就能够这样操做,看代码:
这样咱们就能够看出使用虚拟机的一些状况,看打印输出:
接着咱们就来看下咱们建立的那个空类是怎样的一个状况,能够这样操做:
MyClass myClass = new MyClass(); //打印出相关的对象头信息 System.out.println(ClassLayout.parseInstance(myClass).toPrintable());
得出如下内容:
OK了,相关信息打印出来了,记住这是myclass的相关内部信息,那这些都是啥呢?看上面的图,是否是有个“Object header”啥意思?不就是对象头嘛,而后咱们来看这里:
这是啥?主要就是来看咱们的一个空对象占多大空间,以前也说了,对象头包括对象标记8字节和类型指针8字节,咱们先来看对象标记,是否是这个:
也就是起始位置是0,而后前进4个字节,此时的起始位置就变成了4,接着再前进4个字节,那此时起始位置就成了8,此时对象标记就占8个字节,这没啥问题,接着咱们看,起始位置是8,而后继续前进4字节,到达12的时候,其实此时类型指针就结束了,也就是8到12,类型指针就占了4字节,看这句话:
也就是此时这个对象就占据12个字节,但是不是说占据16个字节才对吗?咱们知道java对象所占大小须要是8字节的整数倍,那为了知足这块,就又对齐填充了4字节,最终达到16字节 。
为何会这样?实际上是由于这里发生了指针压缩,在说这个指针压缩以前,须要明白这样的一东西:
咱们经过代码来讲下:
咱们在空类中加入一个char类型,再看下结果:
接着咱们再看一个:
我就问此时你说会进行对齐填充几个字节?思考一下:
为何是6,必定要想明白了,记住8的倍数哦!对了,一个对象有多大,记得能够看这里:
接着咱们再说以前指针压缩的问题,也就是类型指针是占8个字节的,但是实际上只占了4个字节,这就是指针压缩的问题,这里咱们须要这么一个jvm参数,就是它:
java -XX:+PrintCommandLineFlags -version
咱们执行看下:
也就是默认开启了指针压缩,因此咱们的类型指针才变成了4字节,接着咱们能够把这个指针压缩给关闭掉,能够这样操做:
再看:
此时就正确啦,就是对象标记占8个字节,类型指针也占8个字节,也就是对象头16个字节。
咱们以前说过,一个java对象包括对象头,实例数据和对齐填充,通过咱们上面的讲解,而后在看下面一张图,我相信你能够秒懂:
有没有一种豁然开朗的感受?到了这里就须要分析最后一波,就是value值了,也就是这部分值(注意咱们重点在Mark Word的value值上):
那这里须要再看看一下这张很是重要的图了:
而后再来看咱们这里建立的类:
这就是一个普通的类,没有加锁,也就是最普通的无锁,咱们再看它的对象结构是啥:
咱们主要来看value这部分,这里咱们仍然须要对照Mark Word的结构来看,这里是无锁结构,因此咱们须要看的是这里:
注意重点等下咱们须要看下这个锁标志位,而后下面看一个对照图:
要仔细看这张图了,懂了这个,基本上你就掌握了Mark Word!为了让你更加的清晰,再给你来一张图:
对于一个Java对象而言,Mark Word是至关重要的,并且它是你后续学习并发编程,研究Java中的各类锁须要必会的知识,刚开始可能以为是个新奇陌生的词汇,可是等你慢慢的去接触它。了解它,你会发现它真的能帮你解决不少看起来很难的知识,会让你以为那些看起来很高大上的东西,原来是这么回事啊,好比偏向锁,轻量级锁什么的,总之,做为一个Java程序员,Mark Word是你须要要掌握的!
固然,因为我的水平有限,本片描述可能存在有误的地方,烦请指正,你们共同窗习,一块儿进步!