Java虛擬機管理的內存的區域可由下面這張圖表示
2012101820014328.jpg
這些內存區域可以劃分為線程私有和線程共享兩類:
- 線程私有即是指該內存區域與線程同生共死,且該區域僅對該線程可見.
- 線程共享則是指該內存區域隨虛擬機啟動而開辟,隨虛擬機關閉而釋放,且該區域對所有線程可見.
線程私有
- 程序計數器:
一塊小的內存區域,是當前線程所執行的字節碼的行號指示器.
當實行java方法時,值為虛擬機字節碼指令地址;執行native方法時,值為空. -
虛擬機棧:
從對應關系來看,一個線程對應一個虛擬機棧,而線程的一個方法對應虛擬機棧中的一個棧幀.可表現為下圖:
無標題.png
一個棧幀中儲存了一個方法的局部變量表,操作數棧,動態鏈接,方法出口等.
線程調用一個方法即是一個棧幀入棧,結束一個方法即是一個棧幀出棧. - 本地方法棧:
與虛擬機棧的結構,作用類似,不同的是虛擬機棧執行的是java方法,本地方法棧執行的是native方法.
注:有的虛擬機將二者合二為一.
線程共享
- java堆:
用于存放對象實例和數組. - 方法區:
用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據.
方法區中包含運行時常量池,Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后存放到方法區的運行時常量池中。 -
直接內存:
并不是虛擬機運行時數據區的一部分,也不是Java虛擬機規范中定義的內存區域.(堆外內存)
一個實例對象被創建的過程如下圖所示:
IMG_20170720_132011.JPG
IMG_20170720_132011.JPG
對象的內存布局
- 對象頭
對象頭包括兩部分信息,第一部分用于存儲對象自身的運行時數據,如哈希碼 (HashCode),GC分代年齡,鎖狀態標志,線程持有的鎖,偏向線程ID,偏向時間戳等.
對象頭的另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。
另外,如果對象是一個Java數組,那在對象頭中還必須有一塊用于記錄數組長度的數據,因為虛擬機可以通過普通Java對象的元數據信息確定Java對象的大小,但是從數組的元數據中卻無法確定數組的大小。 - 實例數據
實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內存。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來。 - 對齊填充
對象的大小必須是8字節的整數倍,當不符合時,由占位符填充來保證.
對象的訪問定位
引用有兩種:
-
句柄:
句柄包含了對象實例指針和對象類型指針
927608-20160702110103187-956075011.png -
直接指針:
對象頭中有對象類型指針
927608-20160702110119593-1353417498.png