1. 程式人生 > 實用技巧 >JVM記憶體模型

JVM記憶體模型

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