java虚拟机对象内存分布详解

本文详细介绍了在HotSpot虚拟机中,对象的内存分布包括对象头、实例数据和填充部分。对象头包含了对象运行时数据和类型指针,其中类型指针指向方法区中的对象类型数据。实例数据存储对象的真实信息,而填充部分则用于满足对象起始地址对齐的要求。文章还提及了对象头的Mark Word在不同锁状态下的存储内容,以及对象数据的存储策略和对齐规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在HotSpot虚拟机里,对象的存储布局分为以下三部分。

  • 对象头(Header)中存储的信息类似于计算机网络中的IP数据报的首部,是对对象的一些附加说明标志的信息,与对象的自身定义的数据无关,下边会详细说明。

  • 实例数据(Instance Data)中存储的就是对象真实有效的信息。

  • 对齐填充(Padding)部分没有特别的含义,单纯为了满足虚拟机规定的“对象起始地址必须为8字节的整数倍”的要求而设置。

                            

一.对象头

对象头中包含两部分信息,第一部分为存储对象自身运行时的数据,另一部分为类型指针,如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度。

第一部分又称为“Mark Word”,由于这部分是额外的存储成本,所以为了充分利用这部分的空间,设计者根据对象不同的状态将这部分存储不同的信息,即复用存储空间。不同的状态是根据Mark Word中的标志位区分的,下表即根据状态划分的存储内容。

表1:HotSpot虚拟机对象头 Mark Word
存储内容标志位状态
对象哈希码、对象分代年龄010未锁定
指向锁记录的指针00轻量级锁定
指向重量级锁的指针10膨胀(重量级锁定)
空,不需要记录信息11GC标记
偏向线程ID、偏向时间戳、对象的分代年龄101可偏向

下表为32位Mark Word的详细分布

GC就是垃圾回收状态,其他为对象的锁状态。在这里简单引申一下锁的概念 ,在多线程的情况下,锁在线程安全中扮演着举重轻重的作用。锁分为乐观锁和悲观锁。在java SE1.6中,锁有四种状态,从低到高分别是无锁状态,偏向锁状态,轻量级锁状态,重量级锁,这几个状态会随着竞争状况逐渐升级,锁的级别越高意味着线程对此对象的竞争也就越大。

第二部分类型指针,这个指针就是确定这个对象是哪个类的实例。 但是书中说这个不是必须的,需要对应对象的访问方式

存在的意义在于,栈中对象的引用使用直接指针的时候,该指针指向堆内存中的对象,所以对象头是需要存储它的类云数据指针,这个指针才是指向方法区中对象的类型 数据。

第三部分存储数组的长度部分的长度也随着JVM架构的不同而不同:32位的JVM上,长度为32位;64位JVM则为64位。64位JVM如果开启+UseCompressedOops选项,该区域长度也将由64位压缩至32位。

二.实例数据

这部分存储的就是这个对象的真实数据了,也就是程序代码中定义的字段内容,当然也包括从父类继承下来的字段。而这些信息的存储顺序取决于虚拟机的分配策略。下面介绍虚拟机的分配策略。

基本规则:

         1.存储顺序见下表:默认基本类型在前,按长度由长至短存储,然后就是对象指针引用。相同宽度的字段分配到一起。如果设置了-XX:FieldsAllocationStyle=0(默认是1),那么引用就会放在最前面。

         2.对于同宽度的字段,父类在前子类在后。如果开启CompactFields,那么,子类中较窄的变量就会插到父列的变量的空隙中。

                                                   

三、填充部分 

对齐补充不是必须存在的,就是占位的作用。 由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,这时若实例数据部分没有对齐时,就需要通过对齐填充来补全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值