java运行时数据区域-----对象的内存布局+对象的访问定位

在HostSpot中,java在内存中的布局可以分为三块内存区域,对象头,实例数据,对齐填充。

对象头分为两部分

       第一部分用于存储对象自身的运行时数据,如哈希吗,GC分代年龄,锁状态标志,偏向锁ID,线程持有的锁,偏向时间戳,这部分数据称为Mark Word,但是对象头信息是与对象自身定义的信息无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word被设计成了一个非固定的数据结构,以便在极小的空间存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例如在32位虚拟机中,如果对象处于未锁定状态下,那么Mark Word的32bit中的25位用于存放对象的哈希码,4位用于存放对象的分代年龄,2位用于存放锁标志位,1位固定为0。

       第二部分是类型指针,即对象指向他的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例,如果对象是一个数组的话,那么对象头中还必须要有一块用于记录数组长度的数据,因为虚拟机可以通过普通java对象的元数据信息确定java对象的大小,但是如果是数组的话,无法确定其数组的长度的大小。

对象的访问定位:创建对象之后,就要使用了,一般是通过虚拟机栈中的引用去寻找。但是如何去寻找,由jvm决定,目前主流的访问方式由两种。

1使用句柄记性访问,java堆中会划分出来一块内存作为句柄池,句柄池中有引用到对象实例数据的指针和到对象类型数据的指针,java虚拟机栈中存放的就是句柄地址,而句柄中包含了对象实例数据与类类型数据。

2使用直接指针访问,直接指针直接指向了一块区域,区域中包含对象类型的数据和到对象类型数据的指针。

这两种方式各有优劣

句柄访问是比较稳定,在对象被移动时,只会改变句柄中的实例数据指针,而引用本身并不会被修改。

直接指针访问的最大好处是速度更快,节省了一次指针定位的时间开销,由于GC的对象移动非常的频繁,所以这个减少开销还是非常可观的,所以采用这种还是比较好的。


猜你喜欢

转载自blog.csdn.net/lsm18829224913/article/details/80243677