ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

& 并发编程-3-对象头

2021-07-16 09:33:20  阅读:200  来源: 互联网

标签:状态 java 字节 对象 编程 hashcode 并发 bit


 

toc

并发编程之synchronize原理-对象头

扫盲

存储单位的bit 和 Byte
1.bit(比特)
bit也就是我们不一定听说过的比特,大名鼎鼎的比特币就是以此命名的。它的简写为小写字母 “b” 。
作为信息技术的最基本存储单元,因为比特实在太小了,所以大家生活中并不是经常听到。那么 bit 是什么呢?
电脑是以二进制存储以及发送接收数据的。二进制的一位,就叫做 1 bit。也就是说 bit 的含义就是二进制数中的一个数位,即 “0” 或者 "1"。

2.Byte(字节)
Byte 是字节的英文写法。它的简写为大写字母 “B"。
既然名字叫字节,那肯定跟字符有关系。是的。英文字符通常是一个字节,也就是 1B,中文字符通常是两个字节,也就是 2B。
字节 Byte 和比特 bit 的换算关系是 1 Byte = 8 bit 。

1byte = 8bit
8byte = 64bit
B=byte
b=bit

自己实现一个锁

java对象头分析

所谓锁就是给对象一个标识;而这个标识就是存在对象头当中
这里截取一张hotspot的源码当中的注释

image-20210311102833000

这张图换成人可读的表格如下 此图极其重要

image-20210311102847892

java的对象头在对象的不同状态下会有不同的表现形式,主要有三种状态:无锁状态、加锁状态、GC状态。那么我可以理解java当中的加锁其实可以理解是给对象上锁,也就是改变对象头的状态,如果上锁成功则进入同步代码块。
但是java当中的锁又分为很多种,从上图可以看出大体分为偏向锁、轻量锁、重量锁三种锁状态。这三种锁的效率完全不同(依次降低)

java对象的布局以及对象头

1、利用JOL来分析java的对象布局

首先maven添加JOL的依赖

<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>5
  <version>0.9</version>
</dependency>

A.java 源码

package com.enjoy.entity;
public class A {
}

JOLExample1.java

package com.enjoy.test;
import com.enjoy.entity.A;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

public class Test1 {
  static A a= new A();
  public static void main(String[] args) {
    System.out.println(VM.current().details());
    System.out.println(ClassLayout.parseClass(A.class).toPrintable());
    System.out.println(ClassLayout.parseInstance(a).toPrintable());
 }
}

运行结果:

image-20210311102902351

分析结果1
整个对象一共16B,其中对象头(Object header)12B,还有4B是对齐的字节(因为在64位虚拟机上对象的大小必须是8的倍数),由于这个对象里面没有任何字段,故而对象的实例数据是0B;

  1. 什么叫对象的实例数据?
  2. 对象头里面的12B到底存的是什么?
    首先要明白什么是对象的实例数据很简单:我们可以在A当中添加一个boolean的字段(boolean占1B),然后看结果:

A.java

package com.enjoy.entity;
public class A {
  boolean f;
}

运行结果2

image-20210311102916503

分析结果2
整个对象的大小还是没有改变一共16B(B=byte),其中对象头(Object header)12B,boolean字段f(对象的实例数据)占1B、剩下的3B就是对齐字节。由此我们可以认为一个对象的布局大体分为三个部分分别是对象头(Object header)、对象的实例数据字节对齐;

对象布局:

image-20210311102932268

接下来讨论第二个问题,对象头为什么是12B?这个12B当中分别存储的是什么呢?(不同位数的VM对象头的长度不一样,这里指的是64bit的vm)

2、大小端模式

再接着往下研究对象的时候先要高明白大小端存储,一般家用笔记本都是小端模式,那么什么是小端模式呢?

小端模式:高字节存在高地址,低字节存在低地址。

image-20210311103032345

3、对象头的规范

http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html

上述链接文档部分截图:

image-20210311103111832

image-20210311103130367

首先引用openjdk文档当中对 对象头的解释
上述引用中提到了一个java对象头包含了2个word,并且还包含了堆对象布局、类型、GC状态、同步状态和标识哈希码,具体怎么包含的呢?又是哪两个word?

对象头的结构大概如下图

image-20210311103151035

mark word为第一个word根据文档可以知他里面包含了锁的信息,hashcode,gc信息等等
klass word(klass pointer)为对象头的第二个word主要指向对象的元数据,他是一个指针;

假设我们理解一个对象头主要上图两部分组成(数组对象除外,数组对象的对象头还包含一个数组长度),那么一个java的对象头多大呢?我们从JVM的源码注释中得知到一个mark word一个是8字节, 64位,那么klass的长度是多少呢?(12-8=4byte)(对象头(Object header)一共12B)
所以我们需要想办法来获得java对象头的详细信息,验证一下他的大小,验证一下里面包含的信息是否正确。

java代码 Test1

public class Test1 {
  static A a= new A();
  //-XX:BiasedLockingStartupDelay=0
  public static void main(String[] args) throws InterruptedException {
    log.debug("----hashcode before");
    log.debug(ClassLayout.parseInstance(a).toPrintable());
    //转化成16进制,方便比较
    log.debug(Integer.toHexString(a.hashCode()));
    log.debug("----hashcode after");
    //计算完hashcode之后的a对象的布局
    log.debug(ClassLayout.parseInstance(a).toPrintable());
 }
}

运行结果

image-20210311103255722

http://tool.oschina.net/hexconvert/ 进制转换

分析结果3:

没有进行hashcode之前的对象头信息,可以看到2b-8b之前的的56bit是没有值,打印完hashcode之后行就有值了,为什么是2-8B,不应该是1-7B呢?因为是小端存储。那么第一个字节当中的八位分别存的就是分带年龄、偏向锁信息,和对象状态,这个8bit分别表示的信息如下图;这个图会随着对象状态改变而改变,下图是无锁状态下

image-20210311103309408

其中的是否可偏向标识在无锁情况下会根据是否计算hashcode而变化;
因为如果计算了hashcode之后对象便变得不可偏向;为什么?

关于对象状态一共分为五种状态,分别是无锁不可偏向、无锁可向锁、轻量锁、重量锁、GC标记,那么2bit,如何能表示五种状态(2bit最多只能表示4中状态分别是:00,01,10,11),jvm做的比较好的是把是否可偏向表示为一个状态,然后根据图中偏向锁的标识再去标识是可偏向的还是不可偏向的

00 轻量锁
01 无锁/偏向锁
10 重量锁
11 GC标记

关于对象头目前只要了解这些就够了,下节课来解释什么是偏向锁,工作原理是什么和轻量锁的性能对比

这节课只要知道对象头里面存了什么东西就可以了;
关于课上做的那个锁的膨胀的实验大家可以自己用JOL去看看,锁的膨胀非常复杂,我只是先大概的给大家演示了一下膨胀过程过程具体大概如下图(切记这个图不能作为面试,只是一个过渡结果,实际锁的膨胀远比这个复杂的多了多)

image-20210311102507109

标签:状态,java,字节,对象,编程,hashcode,并发,bit
来源: https://www.cnblogs.com/doagain/p/15018627.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有