JVM運行時數據區
線程私有的數據區
程序計數器
虛擬機棧
本地方法棧
所有線程共有的數據區
Java堆
方法區
線程私有的數據區
程序計數器
虛擬機棧
本地方法棧
所有線程共有的數據區
Java堆
方法區
事實上,JVM在執行Java代碼時都會把內存分為幾個部分,即數據區來使用,這些區域都擁有自己的用途,並隨着JVM進程的啟動或者用戶線程的啟動和結束建立和銷毀。接下去,通過下面的這幅圖,我們一個一個細數一下JVM運行時的數據區結構。
圖一:JVM運行時的數據區結構
JVM運行時數據區
線程私有的數據區
程序計數器
- 作用
記錄當前線程所執行到的字節碼的行號。字節碼解釋器工作的時候就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。 - 意義
JVM的多線程是通過線程輪流切換並分配處理器來實現的,對於我們來說的並行事實上一個處理器也只會執行一條線程中的指令。所以,為了保證各線程指令的安全順利執行,每條線程都有獨立的私有的程序計數器。 - 存儲內容
當線程中執行的是一個Java方法時,程序計數器中記錄的是正在執行的線程的虛擬機字節碼指令的地址。
當線程中執行的是一個本地方法時,程序計數器中的值為空。 - 可能出現異常
此內存區域是唯一一個在JVM上不會發生內存溢出異常(OutOfMemoryError)的區域。
虛擬機棧
- 作用
描述Java方法執行的內存模型。每個方法在執行的同時都會開辟一段內存區域用於存放方法運行時所需的數據,成為棧幀(即一個方法一個棧幀),
一個棧幀包含如:局部變量表、 操作數棧、動態鏈接、方法出口等信息。
局部變量表: (該方法中所有的變量) 每個定長單元可以存儲最大32位的數據,因為方法中的變量類型和個數都已經確定了,所以局部變量表在編譯時即可確定大小。
可以直接存儲8大基本類型,存儲引用類型時,需要在堆中新創建一個對象,然后存儲這個對象的所在地址。
動態鏈接:比如類的多態,或者一些在運行時才能確定的具體實現,IOC等。用以確定最終的執行對象。
- 意義
JVM是基於棧的,所以每個方法從調用到執行結束,就對應着一個棧幀在虛擬機棧中入棧和出棧的整個過程。 - 存儲內容
局部變量表(編譯期可知的各種基本數據類型、引用類型和指向一條字節碼指令的returnAddress類型)、操作數棧、動態鏈接、方法出口等信息。
值得注意的是:局部變量表所需的內存空間在編譯期間完成分配。在方法運行的階段是不會改變局部變量表的大小的。 - 可能出現的異常
如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常。
如果在動態擴展內存的時候無法申請到足夠的內存,就會拋出OutOfMemoryError異常。本地方法棧
- 作用
為JVM所調用到的Nativa即本地方法服務。 - 可能出現的異常
和虛擬機棧出現的異常很相像。
所有線程共有的數據區
Java堆
- 作用
所有線程共享一塊內存區域,在虛擬機開啟的時候創建。 - 意義
1、存儲對象實例,更好地分配內存。
2、垃圾回收(GC)。堆是垃圾收集器管理的主要區域。更好地回收內存。
-存儲內容
存放對象實例,幾乎所有的對象實例都在這里進行分配。堆可以處於物理上不連續的內存空間,只要邏輯上是連續的就可以。
值得注意的是:在JIT編譯器等技術的發展下,所有對象都在堆上進行分配已變得不那么絕對。有些對象實例也可以分配在棧中。 - 可能出現的異常
實現堆可以是固定大小的,也可以通過設置配置文件設置該為可擴展的。
如果堆上沒有內存進行分配,並無法進行擴展時,將會拋出OutOfMemoryError異常。
方法區
- 作用
用於存儲運行時常量池、已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。 - 意義
對運行時常量池、常量、靜態變量等數據做出了規定。 - 存儲內容
運行時常量池(具有動態性)、已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。 - 可能出現的異常
當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。