10.Java对象内置结构

Java对象内置结构

Java对象很多重要信息都存放在对象结构中,在学习Java内置锁之前,先来了解一下Java对象结构

1.Java对象的三个部分

1.1.对象头

对象头一共包括三个字段【Mark Word】【Class Pointer】【 Array Length】

  • MarkWord(标记字),用于存储自身运行时的一些数据,例如GC标志位,哈希码,锁状态等信息。
  • Class Pointer(类对象指针),用于存放此对象的元数据(InstanceKlass)的地址,虚拟机可以通过此指针确当这个对象是那个类的实例
  • Array Length(数组长度),如果对象是一个Java数组,那么此字段必须有,用于记录数组长度的数据,如果不是数组,那么此字段不存在

1.2.对象体

对象体包含了,对象的实例变量(成员变量),用于成员属性值,包括父类的成员属性值,这部分内存按照4字节对齐

1.3.对齐字节

对齐字节(Alignment Byte)是为了优化内存访问效率而在Java中自动添加的额外字节。它确保对象和数组字段的对齐,提高内存访问的效率和性能。开发人员无需手动处理对齐字节,由Java虚拟机自动处理。

其中,对齐字节也称为填充对齐,作用就是用来保证Java对象在所占用内存字节数为8的倍数(8N Bytes),HotSopt VM内存管理要求,对象的起始地址必须是8字节的整数倍

在这里插入图片描述

2.对象结构中核心字段的作用

下面我们来对Object实例结构中的几个重要字段作一些简单说明

2.1.MarkWord(标记字)

在Java对象头部的一部分内存空间用于存储对象的元数据和状态信息,被称为MarkWord。MarkWord包含了对象的哈希码、锁信息、GC标记等信息。它的具体结构和内容在不同的JVM实现中可能会有所差异。

2.2.Class Pointer(类对象指针)

在Java对象头部的另一部分内存空间用于存储指向该对象所属类的指针,被称为Class Pointer。这个指针指向对象的类的元数据,包括类的方法、字段等信息。通过Class Pointer,可以在运行时获取对象所属的类,并进行相应的操作。

2.3.Array Length(数组长度)

对于数组对象,Java对象头部的一部分内存空间用于存储数组的长度信息。这个长度信息在创建数组时被初始化,之后无法被修改。

2.4.对象体

象体是Java对象的实际数据部分,包含了对象的字段值。对象体的大小取决于对象中定义的字段及其类型。对象体紧跟在对象头部之后,占据连续的内存空间。

2.5.对齐字节

在Java对象的内存布局中,为了对齐数据而添加的额外字节被称为对齐字节。对齐字节的存在是为了提高内存访问的效率和性能。它确保对象和数组字段的对齐,使得数据能够被高效地加载到寄存器或缓存中。

3.Mark Word的结构信息

Java内置锁涉及了很多的重要信息,这些都存放在对象结构中,放放于对象头的MarkWord字段中,MarkWord长度为JVM的一个Word大小,也就说32位JVM MakrWord 为32位 ,64位的Mark Word为64位,MarkWord的位长度并不会受到OOP对象指针压缩的影响。

Java内置锁的状态一共分为4种【无锁】->【偏向锁】->【轻量级锁】->【重量级锁】,四种锁的状态会随着竞争的情况逐渐升级,而且过程是不可逆的(不可降级),锁只会升级,不会降级

3.1.不同锁状态下的Mark Word字段结构

Mark Word 字段的结构和Java内置锁的结构 强相关,为了让Mark Word字段存储更多的信息,JVM将Mark Word的最低两个位置设置为Java内置锁状态

下面通过图来了解一下Mark Word 结构

在这里插入图片描述

3.2.Mark Word的构成

目前主流的JVM都是64位,使用64位的Mark Word 下面对64位的Mark Word的各部分进行简单介绍下

  1. **lock(锁状态):**lock字段用于表示对象的锁状态。它包含了对象的锁信息,可以标识对象是否被锁定,以及锁的类型(如无锁、偏向锁、轻量级锁、重量级锁等)。锁状态的具体取值和意义在不同的JVM实现中可能会有所差异。
  2. biased_lock(偏向锁标记):biased_lock字段用于表示对象是否启用了偏向锁。偏向锁是一种针对无竞争的情况下优化的锁机制,用于提高单线程访问同步块的性能。当对象启用偏向锁时,biased_lock字段的值为1,表示该对象已经偏向于某个线程,不需要进行锁的竞争。
  3. **age(对象年龄):**age字段用于表示对象的年龄。在垃圾回收的过程中,JVM会根据对象的年龄来决定是否将对象晋升为老年代。对象的年龄通过age字段进行记录,当对象经过一次Minor GC(年轻代垃圾回收)而没有被回收时,其年龄会增加。
  4. **identity_hashcode(标识哈希码):**identity_hashcode字段用于存储对象的标识哈希码。标识哈希码是对象的一个唯一标识,与对象的内容无关。它在需要比较对象的引用是否相等时起到重要的作用。
  5. **thread(持有锁的线程):**thread字段用于记录当前持有锁的线程。在多线程环境下,当一个线程获得对象的锁时,该字段会记录该线程的引用,以便在锁的释放或竞争时进行相应的操作。
  6. **epoch(锁记录的版本号):**epoch字段用于记录锁记录的版本号。它在偏向锁撤销和轻量级锁升级为重量级锁时起到重要作用。当锁状态发生变化时,会更新epoch字段的值,以确保锁记录的有效性。
  7. **ptr_to_lock_record(指向锁记录的指针):**ptr_to_lock_record字段用于指向对象的锁记录。锁记录是在竞争过程中创建的数据结构,用于记录锁的状态和竞争情况等信息。
  8. **ptr_to_heavyweight_monitor(指向重量级监视器的指针):**ptr_to_heavyweight_monitor字段用于指向重量级监视器的指针。当对象的锁升级为重量级锁时,会创建一个重量级监视器来管理锁的竞争。

这些字段在MarkWord中扮演着重要的角色,用于管理对象的锁状态、偏向锁、年龄、哈希码等信息。它们的具体含义和使用方式在不同的JVM实现中可能会有所不同,但它们都对对象的同步和垃圾回收起到了重要的作用。

4.使用JOL工具查看对象的布局

如何在Java程序中查看Object对象头的结构呢?我们可以使用OpenJDK提供的JOL工具

JOL是分析JVM中对象的结构布局的工具,该用具大量使用了Unsafe ,JVMTI来解码内部布局情况,分析结果还是比较准确的。

4.1.引入依赖

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
    <groupId>org.openjdk.jol
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值