理解JVM(一):記憶體結構

Joepis發表於2019-03-04

摘要: 原創出處 https://peijie-sh.github.io 歡迎轉載,保留摘要,謝謝!

在JVM中,記憶體主要被分為5類

JVM記憶體結構.jpg

Heap

  • 虛擬機器記憶體管理中最大的一塊記憶體空間。
  • 存放關鍵字new建立的物件例項和陣列。
  • 堆記憶體被所有執行緒共享。
  • 這塊記憶體區由JVM(Java虛擬機器)自己管理。當使用new建立物件時,不必指定分配空間的大小,JVM會動態自動分配一塊區域;在程式執行過程中,沒有指向此物件的引用時,此物件就被標記為可被回收狀態,將由GC(垃圾回收器)在一個不確定的時間自動回收,釋放所佔的記憶體空間。
  • 從記憶體回收的角度看,垃圾收集器大都基於分代收集演算法,所以堆一般分為新生代老年代,更細緻可劃分為:Eden空間From Survivor空間To Survivor空間

虛擬機器棧VM Stack

  • 存放8種基本型別的資料和物件引用(不是物件)。
  • 每個執行緒有自己的單獨的棧。
  • 先進後出,後進先出。
  • 因為主要存放基本型別資料變數,所以分配空間比堆快。當超出變數的作用域,將由編譯器立即釋放空間。

本地方法棧Native Method Stack

  • 虛擬機器棧類似,虛擬機器棧為虛擬機器呼叫Java方法服務,本地方法棧為虛擬機器呼叫Native方法服務。
  • 在HotSpot虛擬機器實現中,虛擬機器棧本地方法棧被合併為一個區域。

程式計數器 Program Counter Register

一塊較小的記憶體空間,可看作是當前執行緒所執行的位元組碼的 行號指示器。

通過改變計數器的值來選取下一條需要執行的位元組碼指令。(分支、迴圈、跳轉、異常處理、執行緒恢復等)基礎功能都依賴與其完成。

特點:

  • 執行緒私有:因為 Java 虛擬機器的多執行緒是通過 執行緒輪流切換 並 分配處理器執行時間 來實現的,在某一時刻,只會執行一條執行緒。因此,為了執行緒切換後能恢復到正確的執行位置,每條執行緒都需要有一個獨立的程式計數器。
  • 無記憶體溢位:如果執行緒正在執行的是一個 Java 方法,這個計數器記錄的是正在 執行的虛擬機器位元組碼指令的地址;如果正在執行的是 Native 方法,這個計數器值則為空(Undefined)。此記憶體區域是唯一一個在 Java 虛擬機器程式規範中沒有規定任何 OutOfMemoryError 情況的區域。

方法區Method Area

  • 跟堆一樣,被所有的執行緒共享。
  • 是一個記憶體邏輯區域,用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。

執行時常量池Runtime Constant Pool

  • 方法區的一部分。
  • Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。

直接記憶體Direct Memory

直接記憶體不是虛擬機器執行時資料區的一部分,也不是Java虛擬機器規範中定義的記憶體區域。 但是這部分記憶體也被頻繁地使用,而且也可能導致OutOfMemoryError異常出現。

在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩 衝區(Buffer)的I/O方式,它可以使用Native函式庫直接分配堆外記憶體,然後通過一個儲存 在Java堆中的DirectByteBuffer物件作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著 提高效能,因為避免了在Java堆和Native堆中來回複製資料。

相關文章