2 HotSpot虛擬機中的對象
2.1 對象的創(chuàng)建
????????1. 虛擬機遇到一條new指令時, 會先檢查該指令的參數(shù)是否能定位到常量池中的類的符號引用, 檢查這個符號引用的類是否已經(jīng)加載、解析、初始化, 如果沒有,需要進行類的加載過程.
????????2. 類加載完成后, 需要為對象分配內存空間, 對象所需要的內存空間在類加載完成后就完全確定.
分配內存的方式: ? ??
????1. 指針碰撞:如果堆內存絕對規(guī)整,已使用的內存放在一邊,未使用的放在另一邊,分配新內存就是移動分界點的指示器. ? ??
????2. 空閑列表:如果堆內存不規(guī)整,需要維護一個列表記錄未使用的內存區(qū)域,查找分配一個足夠大區(qū)域給新對象,然后更新列表.
堆是否規(guī)整取決于垃圾回收器是否具有壓縮整理功能.
分配內存的過程如何避免并發(fā)安全問題: ? ??
????1.對分配內存的過程進行加鎖 (虛擬機通過CAS加上失敗重試保證更新操作的原子性). ? ??
????2.TLAB(可通過參數(shù)開啟):提前按照線程分配不同的堆空間, 稱為本地線程分配緩沖.哪個線程需要分配對象內存就在哪個線程中分配,只有當TLAB用盡, 產生新的TLAB時才需要加鎖. 對象內存空間分配完成后, 會將該空間置為零值, 若果需要TLAB, 該過程提前到TLAB分配時.此時對象的屬性已經(jīng)被賦予零值. ? ? ? ?
? ? ????3. 對象的初始化, 對象已經(jīng)產生, 但由于沒有調用構造方法, 此時的對象還不是我們想要的.等到<init>
方法調用完成該對象才算結束創(chuàng)建,?并可真正的被使用.
2.2 對象的內存布局
堆中的對象包含3部分:
1. 對象頭: ? ? ? ?
????- Mark Word ? ? ? ?
????- 類信息的指針:不一定有, 這取決于對象的訪問方式, 使用句柄池進行訪問的話, 對象的對象頭是不會去存儲指向方法區(qū)中類型數(shù)據(jù)的指針的,?詳情在下文的2.3可見.? ? ??
????- 數(shù)組長度:不一定有, 當堆中存儲的是數(shù)組對象時,會有該部分.?
2. 實例數(shù)據(jù):對象真正存儲的有效數(shù)據(jù), 各種類型字段(包括父類繼承的)?
3. 對齊填充:該部分并不是必須的, 起到占位符的作用, hotspot要求對象占用的空間需要是8個字節(jié)的整數(shù)倍,對象頭正好符合, 如果實例數(shù)據(jù)沒有對齊, 就通過對齊填充補全.
下圖是mark word在64位虛擬機中, 在不同鎖狀態(tài)的記錄.

關于不同的鎖狀態(tài), 涉及Java中鎖的膨脹,?以后會提這件事.
2.3 對象的訪問定位
棧中的引用型變量需要定位到堆中的對象,
使用句柄
在堆中創(chuàng)建句柄池, 在句柄池中擁有對象實例數(shù)據(jù)指針和對象類型數(shù)據(jù)指針, 對象實例數(shù)據(jù)指針指向堆中的對象, 對象類型指針指向方法區(qū)中對象的類型信息.
直接訪問
直接訪問時, 堆中不需要創(chuàng)建句柄池, 棧中引用型變量直接指向堆中的對象, 在對象中的對象頭里存儲指向對象所屬類型的指針, 用來訪問方法區(qū)的類型數(shù)據(jù).


兩種訪問方式各有優(yōu)勢, 使用句柄池雖然會多一次指針定位的開銷, 但是當堆中對象位置發(fā)生改變時, 只需要改變句柄池中對象的引用, 不需要改動棧中局部變量表的reference變量的指向; 直接訪問的方式與之優(yōu)勢相反.HotSpot使用的是直接訪問的方式.