java虚拟机学习之(四)对象访问定位

创建对象是为了访问对象,那么对象是通过何种方式被访问的呢?

前面我们已经对对象的创建过程进行了介绍,但是对于对象的信息的存储位置可能还是不太清楚。下面就先介绍一下对象创建过程中,对象在内存区域的存储,以便我们了解对象的访问。

1.对象创建回顾

Object obj = new Object();

现在假设上述语句出现在方法体中,“Object obj”这部分将会反应到java栈的本地变量表中,作为一个reference类型数据出现。而“new Object()”这部分将会反应到java堆中,形成一块存储Object类型所有实例数据的结构化存储,根据具体类型以及虚拟机实现的对象内存布局的不同,这块内存的长度是不固定的。另外java堆中还必须能查找到此对象的类型数据信息(如对象类型,父类,实现的接口,方法等,这些信息在类加载的时候被加载到方法区中),所以还必须有一块内存区域(到对象类型数据的指针)指向方法区的类型数据。

总结一下:对象的创建涉及三块内存区域,java栈的本地变量表(线程私有),java堆(存储对象实例数据,所有线程公有),方法区(存储对象类型数据,所有线程公有)。对象创建时,首先检查对象的数据类型是否存在,不存在则执行类加载,将对应类型加载到方法区中,然后执行内存分配等工作并返回对象实例数据在java堆中的地址,最后将对象的引用数据入栈(java栈本地变量表),完成对象创建工作。

2.对象访问

下面正式进行对象访问的讲解。

由于Reference类型在java虚拟机规范中只规定了一个指向对象的引用地址,并没有定义这个引用通过何种方式去定位,访问到java堆中的对象位置,因此不同的虚拟机实现的访问方式可能不同,但是主流的方法有两种:使用句柄和直接指针。

句柄方式访问

如果使用句柄方式访问,java堆中将会划出一块内存区域用来作为句柄池,Reference中存储的就是对象的句柄地址,而 句柄中包含了对象实例数据和对象类型数据的各自的具体地址信息,如下所示(借用一下http://blog.csdn.net/u011130752/article/details/50886939的图):

java虚拟机学习之(四)对象访问定位

直接指针访问:

如果使用直接指针访问,那么Reference中存储的直接就是对象在java堆中的实例数据的地址,那么如此一来,java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,如下所示:

java虚拟机学习之(四)对象访问定位

这两种对象访问方式各有优势,使用句柄方式来访问的最大好处就是reference中存储的信息是稳定的句柄地址,在对象被移动(垃圾收集器移动对象是非常普遍的行为)时只改变句柄中实例数据的指针,而Reference本身不必修改;使用直接指针访问的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在java中非常频繁,因此这类开销积少成多后也是一项非常可观的开销。就sun HotSpot而言,它是使用直接指针方式进行对象访问的。

注:以上内容,部分来自自己的思考,如有不对的地方,望批评指正!