前面学习了Java虚拟机的内存分区,今天来学学Java语言中对象访问是如何进行的。
Java语言中对象访问会涉及Java栈、Java堆、方法区这三个重要内存区域之间的关联关系,如以下代码:
Object obj=new Object();
如果这句代码出现在方法体中,那“ Object obj”中的obj将存储在Java栈上,以一个reference类型数据存在,“new Object()”的对象实例数据将会以结构化数据存储在Java堆上,根据类型以及虚拟机实现的对象内存布局的不同这块内存的长度是不固定的。在Java堆中还包含能够查找到此对象类型(如对象类型、父类、实现的接口、方法等)的地址信息,并且这些类型数据存储在方法区中。我们暂时认为obj的值则指向此对象实例数据在Java堆上的位置。
Java虚拟机规范里面规定reference类型是一个指向对象的引用,没有规定引用到对象的定位和访问方式,不同的虚拟机访问方式有所不同,主流的访问方式有两种:使用句柄和直接指针。
1、使用句柄方式:
使用句柄访问方式,Java堆中会划分出一块内存用作句柄池,reference中存储的就是对象的句柄地址,句柄地址中包含了对象实例数据和类型数据各自的具体地址信息,如图1。
图1 通过句柄方式访问对象
2、使用直接指针方式:
使用直接指针方式,Java堆对象的布局中就必须考虑如何访问类型数据的相关信息,reference中存储的就是对象地址,如图2。
图2 使用直接指针方式访问对象
总结:两种方式各有优势,句柄方式最大的好处就是reference中存储的是稳定的句柄地址,对象被移动(如垃圾收集时移动对象)后只需改变句柄中的实例数据指针,reference本身不需要修改,使用直接指针方式最大的好处就是减少了一次指针定位因此速度更快,但是对象被移动时需要修改reference的值,修改Java栈中的数据看起来就感觉比较复杂实现起来难度会更大吧。