深入理解多线程(三)—— Java的对象头

上一篇文章中我们从HotSpot的源码入手,介绍了Java的对象模型。这一篇文章在上一篇文章的基础上再来介绍一下Java的对象头。主要介绍一下对象头的作用,结构以及他和锁的关系。

Java对象模型回顾与勘误

在上一篇文章中,关于对象头的部分描述有误,我已经在我博客的文章中就行修正 。这里再重新表述一下。

每一个Java类,在被JVM加载的时候,JVM会给这个类创建一个instanceKlass,保存在方法区,用来在JVM层表示该Java类。当我们在Java代码中,使用new创建一个对象的时候,JVM会创建一个instanceOopDesc对象,这个对象中包含了对象头以及实例数据。

这里提到的对象头到底是什么呢?

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
}

上面代码中的_mark_metadata其实就是对象头的定义。关于_metadata之前就介绍过,这里不再赘述。由于这个专题主要想介绍和JAVA并发相关的知识,所以本文展开介绍一下_mark ,即mark word。

对象头信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。

对markword的设计方式上,非常像网络协议报文头:将mark word划分为多个比特位区间,并在不同的对象状态下赋予比特位不同的含义。下图描述了在32位虚拟机上,在对象不同状态时 mark word各个比特位区间的含义。

同样,在HotSpot的源码中我们可以找到关于对象头对象的定义,会一一印证上图的描述。对应与markOop.hpp类。

enum { age_bits                 = 4,
      lock_bits                = 2,
      biased_lock_bits         = 1,
      max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
      hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
      cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
      epoch_bits               = 2
};

从上面的枚举定义中可以看出,对象头中主要包含了GC分代年龄、锁状态标记、哈希码、epoch等信息。

从上图中可以看出,对象的状态一共有五种,分别是无锁态、轻量级锁、重量级锁、GC标记和偏向锁。在32位的虚拟机中有两个Bits是用来存储锁的标记为的,但是我们都知道,两个bits最多只能表示四种状态:00、01、10、11,那么第五种状态如何表示呢 ,就要额外依赖1Bit的空间,使用0和1来区分。

在32位的HotSpot虚拟机 中对象未被锁定的状态下,Mark Word的32个Bits空间中的25Bits用于存储对象哈希码(HashCode),4Bits用于存储对象分代年龄,2Bits用于存储锁标志位,1Bit固定为0,表示非偏向锁。

markOop.hpp类中有关于对象状态的定义:

  enum { locked_value             = 0,
         unlocked_value           = 1,
         monitor_value            = 2,
         marked_value             = 3,
         biased_lock_pattern      = 5
  };

简单翻译一下:

locked_value(00) = 0

unlocked_value(01) = 1

monitor_value(10) = 2

marked_value(11) = 3

biased_lock_pattern(101) = 5

关于为什么要定义这么多状态,上面提到的轻量级锁、重量级锁、偏向锁以及他们之前的关系,会在下一篇文章中重点阐述,敬请期待。

from:https://www.hollischuang.com/archives/1953

原文地址:https://www.cnblogs.com/GarfieldEr007/p/9954859.html

时间: 2024-11-05 17:25:50

深入理解多线程(三)—— Java的对象头的相关文章

多线程(三) java中线程的简单使用

============================================= 原文链接:多线程(三) java中线程的简单使用 转载请注明出处! ============================================= java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依旧是实现了Runnabel接口.考虑到java的

深入理解多线程(二)—— Java的对象模型

上一篇文章中简单介绍过synchronized关键字的方式,其中,同步代码块使用monitorenter和monitorexit两个指令实现,同步方法使用ACC_SYNCHRONIZED标记符实现.后面几篇文章会从JVM源码的角度更加深入,层层剥开synchronized的面纱. 在进入正题之前,肯定有些基础知识需要铺垫,那么先来看一下一个容易被忽略的但是又很重要的知识点 -- Java对象模型 . 大家都知道的是,Java对象保存在堆内存中.在内存中,一个Java对象包含三部分:对象头.实例数

002-多线程-锁-同步锁-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. synchronized结论: 1.java5.0之前,协调线程间对共享对象的访问的机制只有synchronized和volatile,但是内置锁在功能上存在一些局限性,jdk5增加了Lock以及ReentrantLock. 2.java5.0,增加了一种新的机制:显式锁ReentrantLock,注意它

JAVA对象头

#为了防止自己忘记,先记着,之前我一直以为<深入理解JAVA虚拟机>写错了来着. 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding). 也就是说  JAVA对象 = 对象头 + 实例数据 + 对象填充 对象头由两部分组成,一部分用于存储自身的运行时数据,称之为 Mark Word,另外一部分是类型指针,及对象指向它的类元数据的指针. 对象头 = Mark Word + 类型指针 (未开启指

Android中关于JNI 的学习(三)在JNI层访问Java端对象

前面两篇文章简单介绍了JNI层跟Java层的一些对应关系,包括方法名,数据类型和方法名称等,相信在理论层面,能够很好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步的认识,由于表达能力或者理解还是有限,有些地方讲得不是很清楚,如果各位朋友有觉得云里雾里,欢迎大家留言一起学习. 概念上的理解有助于我们更好地认识JNI,而一些实际点的例子则能够更好地帮我们从代码上去掌握并应用JNI. 在第一篇文章,我们是从一个小例子来入门学习的,在其中,我们通过JNI层函数返回

Java 反射理解(三)-- Java获取方法信息

Java 反射理解(三)-- Java获取方法信息 基本的数据类型.void关键字,都存在类类型. 举例如下: public class ClassDemo2 { public static void main(String[] args) { Class c1 = int.class;//int 的类类型 Class c2 = String.class;//String类的类类型,可以理解为String类字节码 Class c3 = double.class; Class c4 = Doubl

java对象结构 对象头 Markword

概述 对象实例由对象头.实例数据组成,其中对象头包括markword和类型指针,如果是数组,还包括数组长度; | 类型 | 32位JVM | 64位JVM| | ------ ---- | ------------| --------- | | markword | 32bit | 64bit | | 类型指针 | 32bit |64bit ,开启指针压缩时为32bit | | 数组长度 | 32bit |32bit | header.png compressed_header.png 可以看到

三种分布式对象主流技术——COM、Java和COBRA

既上一遍,看到还有一遍将关于 对象的, 分布式对象, 故摘抄入下: 目前国际上,分布式对象技术有三大流派--COBRA.COM/DCOM和Java.CORBA技术是最早出现的,1991年OMG颁布了COBRA 1.0标准,在当时来说做得非常漂亮:再有就是Microsoft的COM系列,从最初的COM发展成现在的DCOM,形成了Microsoft一套分布式对象的计算平台:而Sun公司的Java平台,在其最早推出的时候,只提供了远程的方法调用,在当时并不能被称为分布式对象计算,只是属于网络计算里的一

理解多线程

一.理解多线程       多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立.线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单.       具体到java内存模型,由于Java被设计为跨平台的语言,在内存管理上,显然也要有一个统一的模型.系统存在一个主内存(Main Memory), Java中所有变量都储存在主存中