運行時數據區域
程序計數器 Program Counter Register
可以看作是當前線程的字節碼的行號指示器,爲什麼說是當前線程呢?因爲java的多線程是通過線程輪流切換來實現的,爲了切換後能恢復到正確的執行位置,每個線程都要有一個獨立的程序計數器,之間互不影響。這塊內存區域被稱爲“線程私有”的內存。
java虛擬機棧VM Stack
- 我們常說的棧內存就是指虛擬機棧
- 虛擬機棧也是線程私有的
- 生命週期與線程相同
- 描述了java方法執行的內存模型,每個方法執行時,都會創建一個棧幀(stack frame)用於存儲局部變量表、操作數棧、動態鏈接,方法出口等信息,每個方法的調用到完成,對應着棧幀在虛擬機棧中的入棧到出棧的過程
- 局部變量表用於存放基本數據類型(boolean,byte,char,short,int,float,long,double),對象引用,和returnAddress
- 該區域會出現兩種異常:1.如果線程請求的棧的深度大於虛擬機棧所允許的深度,會拋出StackOverflowError異常。2.若虛擬機棧可以動態擴展(大部分虛擬機都允許),如果擴展時無法申請到足夠的內存,則會拋出OutOfMemoryError異常
本地方法棧 Native Method Stack
- 線程私有
- 與虛擬機棧類似,唯一區別就是虛擬機棧位虛擬機執行java方法服務,本地方法棧則虛擬機使用的native方法服務
- 也會拋出StackOverflowError異常與OutOfMemoryError異常
java堆 java heap
- 是一塊被所有線程共享的內存區域,在虛擬機啓動的時候創建。
- 唯一目的就是存放對象(及數組)實例,幾乎所有對象實例都在這裏分配內存
- 在堆中沒有內存完成實例分配,並且堆無法再拓展的時候,就會拋出OutOfMemoryError異常
方法區
- 無法滿足內存分配時就會拋出OutOfMemoryError異常
- 用於存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等
運行時常量池
- 是方法區的一部分
- 常量池:用於存放編譯期生成的各種字面量(1,2,“abc”稱爲字面量)和符號引用,這部分內容在類加載後進入方法區的運行時常量池存放
- 無法滿足內存分配時就會拋出OutOfMemoryError異常
直接內存
- 並不是虛擬機運行時數據區的一部分,是引入NIO類後出現的一塊內存。
虛擬機對象
對象內存分配
- 指針碰撞:要求java堆是規整的!Serial,ParNew
- 空閒列表:虛擬機維護一個列表,記錄哪些內存塊是可用的,分配的時候找到一個空間給對象,並更新列表記錄。CMS
對象的內存佈局
對象在內存中存儲的佈局可以分爲三塊:對象頭,實例數據,對齊填充
* 對象頭:對象自身的運行時數據和類型指針(對象指向他的類元數據的指針)
* 實例數據:對象存儲的有效信息
* 對齊填充:對象的大小必須是8字節的整數倍,因此不夠得需要補齊
對象的訪問定位
java程序需要通過棧中的reference來操作java堆上的具體對象
主流兩種方式來訪問:使用句柄和直接指針
直接指針節省了一次指針定位的時間