1. 程式人生 > >細說JVM系列:JVM物件的建立、記憶體佈局、訪問

細說JVM系列:JVM物件的建立、記憶體佈局、訪問

物件的建立、記憶體佈局、訪問

  這裡會深入探討HotSpot虛擬機器在java堆中的物件分配、佈局和訪問的全過程。

一.物件的建立

  虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。如果沒有,那必須先執行相應的類載入過程。

  在類載入檢查通過後,接下來虛擬機器將為新生物件分配記憶體。物件所需記憶體的大小在類載入完成後便可以完全確定,為物件分配空間的任務等同於把一塊確定大小的記憶體從java堆中劃分出來。

  記憶體分配完成之後,虛擬機器需要將分配到的記憶體空間都初始化為零值。

  接下來,虛擬機器要對物件進行必要的設定,例如這個物件是哪個類的例項、如何才能找到類的元資料資訊、物件的雜湊碼、物件的GC分代年齡等資訊。這些資訊存放在物件的物件頭(Object Header)之中。

  在上面工作完成之後,從虛擬機器的視角來看,一個新的物件已經產生了,但從java程式的視角來看,物件建立才剛剛開始——方法還沒有執行,所有的欄位都還為零。所以,一般來說,執行new指令之後會接著執行方法,把物件按照程式設計師的意願進行初始化,這樣一個真正可用的物件才算完全產生出來。

二.物件的記憶體佈局

  在HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為3塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)。

  HotSpot虛擬機器的物件頭包括兩部分資訊,第一部分用於儲存物件自身的執行時資料,如雜湊碼、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒ID、偏向時間戳等。物件頭的另一部分是型別指標,即物件指向他的類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項。

  接下來的例項資料部分是物件真正儲存的有效資訊,也是在程式程式碼中所定義的各種型別的欄位內容。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來,這部分的儲存順序會受到虛擬機器分配策略引數和欄位在java原始碼中定義順序的影響。

  第三部分對齊填充並不是必然存在的,也沒有特別的含義,它僅僅起著佔位符的作用。

三.物件的訪問

  建立物件是為了使用物件,我們的java程式需要通過棧上的reference資料來操作堆上的具體物件。由於reference型別在java虛擬機器規範中只規定了一個指向物件的引用,並沒有定義這個引用應該通過何種方式去定位、訪問堆中的物件的具體位置,所以物件訪問方式也是取決於虛擬機器實現而定的。目前主流的訪問方式有使用控制代碼和直接指標兩種。

以Object obj = new Object()為例
1.Object obj這部分將對映到java棧的本地變量表中,作為reference型別資料出現。
2.new Object()這部分的語義將會反映到java堆中,形成一個儲存了Object型別所有勢力資料值的結構化記憶體。
3.另外,在java堆中還必須包含能查詢到此物件型別資料(如物件型別、父類、實現的介面、方法等)的地址資訊,這些型別資料則儲存在方法區中。也就是類的資訊。
如何通過棧中的reference型別資料訪問到堆中的對應資料呢?主流的訪問方式有兩種:使用控制代碼和直接指標。

1.使用控制代碼

這裡寫圖片描述

2.使用指標訪問

這裡寫圖片描述