首先,內存模型圖,以下:數組
其次,一句話歸納各個區域的做用:佈局
1:程序計數器(Program Counter Register),讓虛擬機中的字節碼解釋器經過改變計數器的值來獲取下一條代碼指令,好比分支、循環、跳轉、異常處理、線程恢復等;線程
2:Java 虛擬機棧(Java Virtual Machine Stacks),棧頂存放當前方法,裏面有局部變量表,指針
3:本地方法棧(Native Method Stacks),本地方法棧則,是爲虛擬機使用到的Native 方法服務,做用同虛擬機棧。對象
4:Java 堆(Java Heap)是Java 虛擬機所管理的內存中最大的一塊,是被全部線程共享的一塊內存區域。此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。 blog
5:方法區(Method Area)與Java 堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。 接口
一:建立一個引用類型對象的內存圖 內存
Object obj = new Object(); get
假設這句代碼出如今方法體中,那: 編譯器
1:首先包含這個方法體的類首先被加載到方法區中;
2:其次方法體自己被壓棧進虛擬機棧;
3:「Object obj」這部分的語義將會反映到虛擬機棧的本地變量表中,做爲一個reference 類型數據出現。
4:而「new Object()」這部分的語義將會反映到Java 堆中,造成一塊存儲了Object 類型全部實例數據值(Instance Data,對象中各個實例字段的數據)的結構化內存,這塊內存的地址存儲在虛擬機棧。另外,在Java 堆中還必須包含能查找到此對象類型數據(如對象類型、父類、實現的接口、方法等)的地址信息,這些類型數據則存儲在方法區中。
以上過程,用一個更具體的例子,就是建立數組,其內存圖以下:
二:建立二位數組的內存圖
以下,爲了簡單起見,省略了方法區的描述:
三:方法調用內存圖
假設是這樣一段代碼,
public class MethodInvoker {
public static void main(String[] args) {
int re = add(1,2);
System.out.println(re);
}private static int add(int i, int j) {
return i + j;
}
}
其內存圖是以下的,
準備動做是類和方法的信息加載到方法區,接下來,
1:main方法壓棧;
2:方法執行過程當中add方法壓棧,而後方法執行,返回3;
3:add方法被彈棧,main方法打印3;
4:main方法彈棧;
三:自定義引用類型對象建立內存圖
第一步:
第二步:
附件:關於虛擬機棧訪問堆中的數據,有兩種方式,以下:
因爲reference 類型在Java 虛擬機規範裏面只規定了一個指向對象的引用,並無定義這個引用應該經過哪一種方式去定位,以及訪問到Java 堆中的對象的具體位置,所以不一樣虛擬機實現的對象訪問方式會有所不一樣,主流的訪問方式有兩種:使用句柄和直接指針。
若是使用句柄訪問方式,Java 堆中將會劃分出一塊內存來做爲句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據和類型數據各自的具體地址信息,以下圖所示。
若是使用直接指針訪問方式,Java 堆對象的佈局中就必須考慮如何放置訪問類型數據的相關信息,reference 中直接存儲的就是對象地址,以下圖所示