Java虚拟机学习记录(四)-对象的内存布局和访问定位

一、前言

jvm创建对象的过程分为类加载检查,分配对象空间,初始化类空间,设置对象信息,对象初始化。那么在分配对象空间时是如何分配的,怎么保证能够定位到对象的内存位置。

二、对象的内存布局

对象在内存中的布局可以分为三部分:对象头(Object Header),实例数据(Instance Data)和对齐填充(Padding)。

a.对象头

对象头有两部分,一部分是用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
对象头的另外一部分是类型指针,即对象指向他的类元数据的指针(表示这个对象是哪个类实例化出来的)。并不是所有的虚拟机实现都必须在对象数据上保留类元数据的指针。因为查找对象的类元数据信息并不一定要经过对象本身(通过句柄)。另外,如果对象是一个Java数组,那在对象头中还必须要有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的类元数据信息确定Java对象大小,但是数据的类元数据中却无法确定数据的大小。

b.实例数据

存储对象中的各种类型的字段内容以及普通对象的指针(oops,Ordinary Object Pointers)。

c.对象填充

不是必然存在,没有特别意义,作为占位符存在。

三、对象的访问定位

建立对象是为了使用对象,对象的访问是通过栈上的reference数据来操作堆上的具体对象。reference是java虚拟机规范的一个指向对象的引用,但并没有规定如何去具体实现,一般来说,有两种实现方式:句柄和直接指针。

a.句柄

采用句柄方式会在Java堆中开辟出一块句柄池空间,Java栈中的本地变量表中存放着指向句柄池中某一个句柄的reference,然后句柄保存有指向某个实例的指针和指向方法区的对象类元数据。
reference---->句柄------>对象和类元数据,共三次指针定位
这种方式的优点是GC清理垃圾时会移动对象地址,栈中的reference不需要改变只需要改变句柄中指向对象的指针。

b.直接指针访问

reference---->对象实例数据(对象实例数据的对象头包含类元指针)------>类元数据,共两次指针定位
这种方式的优点是速度更快,节省了一次指针定位的时间。Sun HotSpot采用的就是这种对象的访问定位方式。

c.注意

在JDK1.8中,已经完全移除了方法区,类元数据的存储放在了本地内存中,这样就不会再收到方法区大小的限制。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据