【Java】Java對象詳解

 

名詞解釋:

符號引用:符號引用使用一組符號來描述所引用的目標,可以是任何字面量,只要能夠無歧義地定位到該引用目標就行了。由於Java源代碼編譯成字節碼的時候,虛擬機不知道所引用的目標的實際地址,所以需要用一個符號來代替引用的對象。比如說Student類引用了People類,但Student類不知道People類的實際地址,因此用”People“這個字面量來表示這個引用的類,當然實際中並不是用“People”這個字面量來表示的,而是根據虛擬機規範來表示類信息。

直接引用

1、直接引用可以是一個指向引用目標地址的指針

2、地址相對偏移量

3、一個能夠定位到該引用目標的句柄

在JVM類加載過程中的解析階段,虛擬機就會把字節碼中的符號引用替換爲直接引用。

 

一、對象的創建

對象的創建在Java語言層面就是使用new關鍵字就可以創建一個對象,但是在虛擬機層面,創建一個對象主要做了以下幾步工作:

1、檢查new指令的參數是否能在常量池中定義到一個類的符號引用

2、檢查這個符號引用所代表的類是否已經被虛擬機加載、解析和初始化,若沒有,則必須先執行相應的類加載過程

3、加載過程結束後,新生對象所需要的內存已經確定,虛擬機爲該新生對象從堆中分配內存存放該對象

4、分配完內存後,虛擬機將該對象內存空間初始化爲0(不包括對象頭),這也是爲什麼Java中每一種類型數據都有對應的零值

5、虛擬機設置該對象的對象頭,填入對象頭數據,比如該對象是哪個類的實例、如何找到類的元數據、該對象的哈希碼等

6、從虛擬機角度來說,對象創建已經完成,但是對於語言層面來說,對象創建剛開始,對象創建之後,會調用構造方法,依照程序員的想法對該對象進行初始化

 

新對象內存分配方式:

1、指針碰撞(Bump the Pointer):該方式假設對內存是絕對規整的,即已分配的內存在一邊,另一邊則是未分配的內存,並記錄着一個指向這兩塊區域中間的指針,分配內存給新對象時,只需要將該指針向未分配內存方向移動該對象大小的內存區域就行了

2、空閒列表(Free List):該方式維護的內存可以是不規整的,虛擬機維護一張位圖表,用以記錄虛擬機內存的使用情況,分配時從該表中找到一塊足夠大的內存劃分給該對象,並更新表記錄

 

劃分內存時的確保併發線程安全性:

1、採用CAS配上失敗重填的方式保證更新操作的原子性

2、採用TLAB方式,如果一個線程要分配內存,就在該線程的TLAB上分配,當TLAB需要擴展時再進行同步操作擴展TLAB,由於TLAB是線程私有的,所以是線程安全的

 

二、對象的內存佈局

對象在內存中大概可分爲3個部分:對象頭、實例數據和對齊填充

1、對象頭:

(1)存儲自身的運行時數據如hashcode、GC分代年齡、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據在32位和64位機中分別佔32bit和64bit,稱爲“Mark Word”,對於對象的不同狀態,該數據會動態變化

(2)類型指針,即對象指向它的元數據的指針

2、實例數據:即該對象真正存儲的有效數據

3、對齊填充:僅僅起到佔位符作用,對於規定了“數據塊”的虛擬機來說,如果一個數據塊中沒有使用全部空間,則需要用佔位符來填充,以保證塊操作

 

三、對象的訪問定位

對象的訪問定位與虛擬機棧有關,虛擬機棧中存放了局部變量表,其中就有“對象引用”,這就是用來訪問定位一個對象的根據,該對象引用一般有兩種實現方式:句柄和直接指針。

1、句柄訪問

使用這個方式的話,虛擬機會在堆中劃分一塊區域來作爲句柄池,reference數據中存儲的就是該對象的在句柄池中的句柄地址,該句柄又包含了對象實例數據與類型數據各自的具體信息

2、直接訪問

使用直接指針訪問的話,reference中存儲的就是該對象的直接地址了

兩種方式的比較:

句柄最大的好處就是reference中只存放着穩定的句柄地址,在對象地址移動時只需要改變句柄中的實例指針就行了,不需要修改reference本身

而直接指針訪問最大的好處就是速度會更快,因爲只需要訪問一次就可獲取到實例的數據地址,而句柄需要訪問兩次,由於對象訪問非常頻繁,因此這個訪問開銷會積少成多 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章