JVM記憶體模型
阿新 • • 發佈:2020-08-25
JVM記憶體結構
- (執行緒)共享記憶體
- 堆
- 方法區(JDK1.7 永久代(位於虛擬機器資料區) -> JDK1.8 元資料區(位於本地記憶體))
- (執行緒)私有記憶體
- JVM虛擬機器棧
- 本地方法棧
- 程式計數器PC
程式計數器(PC)
-
定義: 當前執行緒正在執行的位元組碼指令的地址。若執行緒正在執行的是本地方法,則為
Undefined
-
作用:
- 位元組碼直譯器通過改變程式計數器依次讀取指令,實現程式碼的流程控制
- 記錄當前執行緒執行位置,方便執行緒的上下文切換
-
特點:
- 記憶體空間佔用小
- 不會出現記憶體溢位錯誤
- 執行緒私有,隨執行緒的建立而建立、銷燬而銷燬
虛擬機器棧(java棧)
-
定義:
- 記錄java方法執行過程的記憶體模型
- 以棧幀為單位為每個方法建立一個記憶體區域:
- 區域性變量表
- 運算元棧
- 動態連結
- 方法出口資訊
- 由於Java 虛擬機器棧是與執行緒對應的,資料不是執行緒共享的,因此不用關心資料一致性問題,也不會存在同步鎖的問題。
-
壓棧出棧過程
- 虛擬機器棧棧頂的棧幀是正在執行的活動棧,表示當前正在執行的方法,PC暫存器會指向這個地址
- 當前方法內部建立區域性變數時,會將區域性變數的值存入棧幀的區域性變量表中
- 當前方法呼叫新的方法時,會新建棧幀壓入棧頂,同上述步驟
- 當前方法退出時,若存在返回值則會進入新棧幀的運算元棧中
-
特點:
- 區域性變量表的大小在編譯時確定並分配記憶體,執行過程中不會變化
- 會出現兩種異常:
- StackOverFlowError 請求棧的深度超過當前 Java 虛擬機器棧的最大深度時
- OutOfMemoryError 執行緒請求棧時記憶體用完了
本地方法棧(C棧)
- 定義:
- 本地方法棧是描述本地方法執行過程的記憶體模型, 很多 Native 方法都是用 C 語言實現的。
堆
-
定義: 堆是用來存放物件的記憶體空間
-
特點:
- 執行緒共享,整個JVM只有一個堆
- 虛擬機器建立時啟動,是垃圾回收的主要場所
- 可分為:
- 新生代(Eden)——From Survior、To Survivor
- 老年代
- Java 堆所使用的記憶體不需要保證是連續的。而由於堆是被所有執行緒共享的,所以對它的訪問需要注意同步問題,方法和對應的屬性都需要保證一致性。
方法區
-
定義: Java 虛擬機器規範中定義方法區是堆的一個邏輯部分。方法區存放以下資訊
- 已載入類資訊
- 常量
- 靜態變數
- 即時編譯器編譯後的程式碼
-
特點:
- 執行緒共享(同堆一樣)
- 儲存一些長期存在不會發生頻繁變動的資訊,也被稱為老年代/元資料區
- 該區域垃圾回收效率低,可以通過設定不允許垃圾回收。主要的回收目標是: 常量池、類的解除安裝
-
執行時常量池:
- 常量
- 靜態變數
- 載入的類資訊
- 即時編譯程式碼
直接記憶體(堆外記憶體)
-
定義: 獨立於java虛擬機器資料區外的記憶體空間
-
操作直接記憶體:
在 NIO 中引入了一種基於通道和緩衝的 IO 方式。它可以通過呼叫本地方法直接分配 Java 虛擬機器之外的記憶體,然後通過一個儲存在堆中的DirectByteBuffer物件直接操作該記憶體,而無須先將外部記憶體中的資料複製到堆中再進行操作,從而提高了資料操作的效率 -
與堆記憶體比較:
- 直接記憶體申請空間耗費更高的效能
- 直接記憶體讀取 IO 的效能要優於普通的堆記憶體。
- 直接記憶體作用鏈: 本地 IO -> 直接記憶體 -> 本地 IO
- 堆記憶體作用鏈:本地 IO -> 直接記憶體 -> 非直接記憶體 -> 直接記憶體 -> 本地 IO