JVM 執行 Java 程序時的內存區域劃分

2019-09-18   IT技術分享

在學習 Java 虛擬機(後面簡稱: JVM )中的垃圾回收機制(GC)之前,先需要了解 在 JVM 中的 Java 程序(class 文件)加載到內存之後到底是怎麼存的。在閱讀了 JVM規範 和周志明的 《深入理解Java虛擬機(第2版)》 之後,總結一下JVM中的內存劃分以及各個區域的作用。

在JVM規範中定義了5種運行時的數據區域:程序計數器(Program Counter Register)、Java虛擬機棧(JVM Stacks)、堆(Heap)、方法區(Method Area)、運行時常量池(Runtime Constant Pool)、本地方法棧(Native Method Stack)。在周志明的書中還提到了直接內存(Direct Memory),它並不是JVM運行時數據區域的一部分,在JVM的規範中也沒有相關的定義。下面分別來說明各自的用途。

程序計數器

程序計數器,也叫PC Register。它的用途很單一,但是卻是很多功能的基礎。如果線程當前執行的是Native方法,那麼寄存器里的值就是Undefined;如果線程當前執行的是非Native方法,那麼寄存器里的值就是當前執行的JVM位元組碼指令的地址。像我們常用的分支、循環、跳轉、異常處理、線程恢復等都依賴於它。

由於JVM支持多個線程同時執行,所以每個線程都有一個獨立的程序計數器,各個線程互不影響,這類內存區域也稱之為 線程私有 的。

Java虛擬機棧

虛擬機棧也是 線程私有 的,隨著一個線程的創建而創建,主要用來存儲棧幀(Stack Frame)。什麼是棧幀呢?在Java中,每個方法在執行時就會先創建一個棧幀並放入虛擬機棧中,在方法執行完畢時再從虛擬機棧中移除該棧幀。它主要用來存儲局部變量表、操作數棧、動態連結、方法出口等信息。我們常說的堆(Heap)和棧(Stack)中的棧,指的就是虛擬機棧。

在JVM規範中並沒有對虛擬機棧空間的大小做限制,可以設置為固定大小的,也可以設置為可擴展的。但是在規範中定義了兩種異常情況:

StackOverflowError
OutOfMemoryError

相比而言,堆在JVM管理的內存區域中屬於最大的一塊,隨著虛擬機的啟動而創建,用來存儲所有的class實例和數組,所有 線程共享 這一區域,該區域也是垃圾回收的主要區域。雖然JVM規範中說所有的對象實例都在該區域分配空間,但是隨著JIT技術的逐步發展,這一說法也不嚴謹了。

堆空間的大小也可以設置為固定大小,或者可擴展的。但不管是何種方式,規範中還是定義了一種異常場景:

  • 如果計算需要更多的堆空間而無法滿足時,則會拋出 OutOfMemoryError 異常。

方法區

方法區和堆一樣,也是隨著虛擬機啟動而創建,所有 線程共享 ,主要用來存儲被JVM加載的類信息、常量、靜態變量等信息。

JVM規範中並未嚴格要求要對該區域進行垃圾回收,但是HotSpot虛擬機在垃圾回收的時候還是會考慮該區域,在分代垃圾回收中所說的「 永久代 」指的就是方法區。方法區的大小也可以設置為固定大小,或者可擴展的。但不管是何種方式,規範中還是定義了一種異常場景:

  • 如果計算需要更多的方法區空間而無法滿足時,則會拋出 OutOfMemoryError 異常。

運行時常量池

運行時常量池是方法區的一部分,用於存儲編譯期生成的各種字面量和符號引用。在Java中並不要求常量一定只有編譯期才能產生,運行期間也可能將新的常量放入池中,例如 String 類的 intern() 方法。

每個運行時常量池都是隨著一個類或者接口的創建而創建的。在規範中定義了一種異常場景:

  • 在創建一個類或者接口時,如果運行時的常量池無法分配到足夠的空間時,則會拋出 OutOfMemoryError 異常。

本地方法棧

本地方法棧和虛擬機棧類似,也是 線程私有 的,隨著一個線程的創建而創建,只不過虛擬機棧是用來服務Java方法調用,而本地方法棧是用來服務本地方法調用的。

在JVM規範中並沒有對本地方法棧空間的大小做限制,可以設置為固定大小的,也可以設置為可擴展的。在規範中也定義了兩種異常情況:

StackOverflowError
OutOfMemoryError

直接內存 *

直接內存不受虛擬機參數的控制,在NIO中有一種基於通道(Channel)與緩衝區(Buffer)的I/O方式,它可以通過Native方法在堆外分配內存,然後通過DirectByteBuffer對象來引用這塊內存。因為避免了在Java堆和Native堆之間來回複製數據,從而在某些場景中能夠得到性能的提升。一旦使用的直接內存超過了物理內存的總和,則會拋出 OutOfMemoryError 異常。

end:如果你覺得本文對你有幫助的話,記得關注點贊轉發,你的支持就是我更新動力。