摘要: 原創出處 https://peijie-sh.github.io 歡迎轉載,保留摘要,謝謝!
在JVM中,記憶體主要被分為5類
堆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堆中來回複製資料。