深入理解Java虛擬機器(二) --- JVM記憶體管理
執行時的資料區域
一.程式計數器
目的:作為當前執行緒所執行位元組碼的行號指示器
原理:通過位元組碼直譯器改變計數器的值來選取下一條位元組碼指令
特點: 1.佔用較小的記憶體空間
2.每條執行緒需要一個獨立的程式計數器
3.Native方法不需要程式計數器,因為它不需要直譯器
4.不同執行緒的該記憶體區域相互獨立
方法型別 | 計數器狀態 |
---|---|
Java方法 | 記錄正在執行位元組碼地址 |
Native方法 | 空 |
異常處理: 當沒有記憶體區域可擴充套件的時候,丟擲OutOfMemoryError
二.Java虛擬機器棧
目的:描述Java執行時的記憶體模型
原理:當一個JAVA方法執行的時候,會在虛擬機器棧上建立一個棧幀,用來儲存 區域性變量表,運算元棧,動態鍵棧,方法出入的資訊(eg:方法返回值)。
特點: 1.廣義上的棧就是指的是,虛擬機器棧中的幾部變量表
2.進入一個方法時,區域性變數空間是確定的,不會再改變
3.不同執行緒的該記憶體區域相互獨立
異常處理:
1.若執行緒請求的棧深度 > 虛擬機器允許的深度,丟擲StackOverflowError
2.若動態虛擬機器棧可以動態擴充套件(絕大多數),若擴充套件時無法申請足夠的記憶體,丟擲 OutOfMemoryError
區域性變量表:
目的
原理:是一個以字長為單位的陣列,用於存放方法引數 和 方法內定義的區域性變量索引
索引型別包括:基本變數型別,物件引用型別, returnAdress型別
1.reference型別(物件引用型別),作為物件引用指標,指明瞭物件在 JAVA堆 中的起始地址 和在 方法區 的物件型別資料 2. returnAdress型別,指向一條位元組碼指令的地址
-
區域性變量表中一個slot代表一個變數槽,長度和CPU架構的位長是相同的。
-
64位長度的long和double型別佔用2個區域性變量表空間(slot),其他的均為1個單位大小。
-
在第0位slot處存放該方法所屬物件例項的引用(在Java堆中),程式中用
this關鍵字
進行訪問 -
可複用:超出作用域的slot變數將被GC回收進行覆寫
運算元棧
目的:作為JVM的工作區,對資料進行操作。
原理:同樣也是一個以字長為單位的陣列,用於存放運算元的值。大多數指令都要從這裡彈出資料,執行運算,然後把結果壓回運算元棧。
解析:
void Method(){
int a = 1;
int b = 2;
int result = a + b;
}
內部過程
1.在區域性變量表分配三個slot,分別指向 a , b,result。其中 a,b有初值
2.將區域性變量表中的a,b的值放入運算元棧。
3.在運算元棧中彈出a,b的值彈出進行運算,接著將結果壓入運算元棧中。
4.從運算元棧彈出結果,放到區域性變量表中result相應的位置
三.本地方法棧
目的:描述Native方法執行時的記憶體模型
原理: 形如Java虛擬機器棧
特點: 不同執行緒的該記憶體區域相互獨立
異常處理: 與Java虛擬機器棧出現的異常是相同的
有些虛擬機器會將本地方法棧與Java虛擬機器棧合二為一(eg:HotSpot虛擬機器)
四.Java堆
目的: 存放幾乎所有物件的例項
原理: 將例項存放在一塊 物理不連續,但是邏輯上連續的記憶體空間上。
特點: 1.是JVM管理的記憶體中最大的一塊區域
2.所有執行緒共享一塊記憶體區域
異常處理: 通常例項分配的時候,堆是可擴充套件的,但是當無法再擴充套件的時候,會丟擲OutOfMemoryError
五.方法區(非堆)
目的: 作為Java堆的邏輯部分
原理: 儲存已被虛擬機器載入的 類資訊,常量,靜態變數,即時編譯器編譯後的程式碼 等資料
特點: 1.物理不連續
2.所有執行緒共享一塊記憶體區域
3.可以選擇不實現GC
異常處理: 雖然方法區是可以擴充套件的,但是當無法滿足記憶體分配時,丟擲OutOfMemoryError
執行時常量池
目的: 是方法區的一部分,用於存放編譯期間生成的各種字面量與符號
原理: 在類載入後,將“常量”存放在該區域
特點: 動態性:在執行期間也能將新的常量放入池中
eg:String類的intern方法(TODO )
JDK1.8後字串常量池放到了堆中,不再是在方法區中,而是在Java堆中
直接記憶體
目的: 直接引用分配在Java堆外Native函式庫的記憶體,避免了Java堆與Native堆來回複製操作
原理: 通過一個儲存在Java堆中的DirectByteBuffer
物件,作為這塊記憶體的引用進行操作
特點: 顯然直接記憶體分配不受Java堆大小限制,但受到本機物理的記憶體大小限制。
異常處理: 當佔用總和超出實體記憶體大小限制的時候,丟擲OutOfMemoryError