对象内存布局(HotSpot)
概述
布局划分为三部分:对象头(Header)、实例数据(Instance)、对齐填充(Padding)
对象头包含两类信息:用于存储对象自身的运行时数据(Mark Word)和对象指向它的类型元数据的指针(类型指针)
实例数据部分时对象真正存储的有效信息,存储顺序受JVM分配策略参数和字段在java源码中定义顺序的影响,
HotSpot默认存储顺序:long/double,int,short,char,byte/boolean,oop(Ordinary Object Pointer)
对齐填充部分不是必须存在,也没有任何含义,仅仅用于占位符
对象头(Header)
对象自身的运行时数据(Mark Word)
这部分数据的长度在32位和64位的未开启压缩指针的JVM中分别为32bit和64bit。
Mark Word是一个有着动态定义的数据结构,目的在于在极小的空间存储更多的数据,根据对象的状态复用自己的存储空间
32位HotSpot中,如果对象未被同步锁锁定的状态下,Mark Word的32bit存储空间中,25bit用于存储对象哈希码,4bit存储对象分代年龄,2bit存储锁标志位,1bit固定为0。其他状态存储内容如下表
锁状态25bit4bit1bit2bit
23bit2bit是否偏向锁锁标志位
无锁对象的HashCode分代年龄001
偏向锁线程IDEpoch分代年龄101
轻量级锁指向栈中锁记录的指针00
重量级锁指向重量级锁的指针10
GC标记空11
类型指针
JVM通过这个指针来确定该对象是哪个类型的实例
并不是所有JVM实现都必须在对象数据上保留类型指针。
如果对象是数组,对象头中还必须有一块用于记录数组长度的数据
New对象()
JVM创建对象过程
对象查找
概述
reference类型在JVM规范中只规定了它是一个指向对象的引用,并没有定义这个引用应该通过什么方式去定位、访问到堆中对象的具体位置
主流访问方式有:使用句柄和直接指针
通过句柄访问
JVM将在队中划分除一块内存作为句柄池,reference中存储对象的句柄地址,而句柄包含了对象实例和类型数据各自的地址信息
优势是:reference存储的是稳定句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而本身不用被修改
通过直接指针访问
堆中的内存布局必须考虑如何放置访问类型数据的相关信息,reference存储的就是对象地址
访问对象本身,不需要多一次间接访问开销,相对句柄,速度块,节省了一次指针定位的时间开销
Hotspot主要使用此方法访问