java对象结构

 

java对象结构分为三部分:对象头对象体对齐字节

三个部分的作用:

1、对象头中的Mark Word(标记字)主要用来表示对象的线程锁状态,另外还可以用来配合GC、存放该对象的hashCode;

2、Klass Word是一个指向方法区中Class信息的指针,意味着该对象可随时知道自己是哪个Class的实例

3、数组长度也是占用64位(8字节)的空间,这是可选的,只有当本对象是一个数组对象时才会有这个部分

4、对象体是用于保存对象属性和值的主体部分,占用内存空间取决于对象的属性数量和类型;

5、对齐字是为了减少堆内存的碎片空间(不一定准确)。

对象头中Mark World、Klass Word、数组长度作用详解:

【1】Mark Word标记字:

以上是Java对象处于5种不同状态时,Mark Word中64位的表现形式,上面每一行代表对象处于某种状态时的样子。

其中各部分的含义如下:

lock2bit的锁状态标记位,由于希望用尽可能少的二进制位表示尽可能多的信息,所以设置了lock标记。该标记的值不同,整个Mark Word表示的含义不同。biased_locklock一起,表达的锁状态含义如下:

biased_lock对象是否启用偏向锁标记,只占1bit。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。lock和biased_lock共同表示对象处于什么锁状态

age:4bit的Java对象年龄。在GC中,如果对象在Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。由于age只有4位,所以最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的原因。

identity_hashcode:31bit的对象标识hashCode,采用延迟加载技术。调用方法System.identityHashCode()计算,并会将结果写到该对象头中。当对象加锁后(偏向、轻量级、重量级),MarkWord的字节没有足够的空间保存hashCode,因此该值会移动到管程Monitor中。

thread:持有偏向锁的线程ID。

epoch:偏向锁的时间戳。

ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。

ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针。

(这一部分还是看另一篇博客:synchronized关键字-个人理解分析)

通常说的通过synchronized实现的同步锁,真实名称叫做重量级锁。但是重量级锁会造成线程排队(串行执行),且会使CPU在用户态和核心态之间频繁切换,所以代价高、效率低。为了提高效率,不会一开始就使用重量级锁,JVM在内部会根据需要,按如下步骤进行锁的升级

        1.初期锁对象刚创建时,还没有任何线程来竞争,对象的Mark Word是下图的第一种情形,这偏向锁标识位是0,锁状态01,说明该对象处于无锁状态(无线程竞争它)。

        2.当有一个线程来竞争锁时,先用偏向锁,表示锁对象偏爱这个线程,这个线程要执行这个锁关联的任何代码,不需要再做任何检查和切换,这种竞争不激烈的情况下(准确的说:只有一个线程没有竞争的情况下),效率非常高。这时Mark Word会记录自己偏爱的线程的ID,把该线程当做自己的熟人。如下图第二种情形。

        3.当有两个线程开始竞争这个锁对象,情况发生变化了,不再是偏向(独占)锁了,锁会升级为轻量级锁,两个线程公平竞争,哪个线程先占有锁对象并执行代码,锁对象的Mark Word就执行哪个线程的栈帧中的锁记录。如下图第三种情形。

        4.如果竞争的这个锁对象的线程更多,导致了更多的切换和等待,JVM会把该锁对象的锁升级为重量级锁,这个就叫做同步锁,这个锁对象Mark Word再次发生变化,会指向一个监视器对象,这个监视器对象用集合的形式,来登记和管理排队的线程。如下图第四种情形。

【2】Klass Word 类指针

这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例

Klass长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位
如果应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64位的JVM将会比32位的JVM多耗费50%的内存。为了节约内存可以使用选项 +UseCompressedOops 开启指针压缩,其中,oop即ordinary object pointer普通对象指针。

开启该选项后,下列指针将压缩至32位:

每个Class的属性指针(即静态变量)
每个对象的属性指针(即对象变量)
普通对象数组的每个元素指针
当然,也不是所有的指针都会压缩,一些特殊类型的指针JVM不会优化,比如指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。

【3】数组长度

如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,这部分数据的长度也随着JVM架构的不同而不同:32位的JVM上,长度为32位;64位JVM则为64位

64位JVM如果开启 +UseCompressedOops选项,该区域长度也将由64位压缩至32位。

 

 

转载自:

Java对象结构与锁实现原理及MarkWord详解:https://blog.csdn.net/scdn_cp/article/details/86491792#comments

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值