1. 程式人生 > >深入理解Java虛擬機器(二) --- JVM記憶體管理

深入理解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