前面學習了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棧中的數據看起來就感覺比較複雜實現起來難度會更大吧。