運行時數據區域
在Java程序運行時,Java虛擬機將其管理的內存劃分爲不同的運行時數據區域:
程序計數器
如果對計算機組成有所瞭解的話,應該很容易理解程序計數器(PC),可以認爲其中的數據就是下一條指令的地址(字節碼行號),在當前指令執行完畢後,JVM會根據PC中的數據找到下一條指令。除此以外,在當前線程被中斷後恢復時,JVM也要根據PC中的值恢復現場。該內存區域並沒有規定任何OOM的情況。
虛擬機棧
在一個線程中,每當開始執行一個普通的Java方法時,虛擬機會爲該線程創建一個棧幀(Stack Frame),並將其放入該線程所屬的虛擬機棧中。當該方法執行完成後,對應的棧幀就會出棧。
棧幀中保存了方法的局部變量表、操作數棧、動態連接、方法出口等信息。
- 局部變量表:存放方法參數和方法內部定義的局部變量。該表的容量以變量槽(Variable Slot)爲單位,一個變量槽能夠存放一個boolean、btye、char、short、int、float、reference或returnAddress類型的數據,而一個變量槽的實際內存大小取決於處理器、操作系統和虛擬機的實現。
- 操作數棧:用於執行過程中保存操作數和結果。如做算數運算時存放操作數,或者在調用其他方法時存放參數。
- 動態連接:運行時常量池中有一部分方法的引用在運行時才轉化爲直接引用,這部分的引用就稱爲動態連接。、
- 方法出口:也叫方法返回地址。即該方法在執行完畢後,下一條應該執行的指令的地址。
該區域有兩種可能的異常狀況:
- 如果線程請求的棧深度大於虛擬機所允許的深度,拋出StackOverFlow異常
- 如果虛擬機棧容量可以動態擴展,當棧擴展時無法申請到足夠的內存會拋出OutOfMemeoryError異常
本地方法棧
本地方法棧的作用與虛擬機棧很相似,區別在於當執行的方法是本地方法時,棧幀會被壓入本地方法棧。甚至有的虛擬機在實現時直接將其與虛擬機棧合併。
Java堆
Java堆用來存放幾乎所有的對象實例,所有線程共享這一區域。垃圾收集器(Garbage Collector)管理的就是Java堆中的對象。
Java堆可以被實現爲固定大小,也可以是可擴展的。如果Java堆的空間已不夠用,並且也無法擴展時,JVM會拋出OutOfMemoryError異常。
方法區
方法區用於存儲被虛擬機加載的類型信息、常量、靜態變量、即時編譯器變異後的代碼緩存等數據,所有線程共享這一區域。
其中,類型信息包含:類的元信息(類的完整名稱,修飾符,父類,接口等),類型的常量池,字段信息,方法信息,類變量,指向加載器的引用,指向Class實例的引用等。
如果方法區無法滿足新的內存分配需求時,將拋出OutOfMemoryError異常。
運行時常量池
運行時常量池是方法區的一部分,用於存放編譯時期產生的各種字面量(常量)與符號引用。這些常量在編譯時期由編譯器生成在Class文件中的常量池表中,JVM在運行時將其複製到運行時常量池中。
總結
數據區域 | 存放內容 | 產生時期/銷燬時期 | 可擴展 | 異常狀況 |
---|---|---|---|---|
程序計數器 | 下一條指令“地址” | 線程生成/線程銷燬 | 不可擴展 | 無 |
虛擬機棧 | 棧幀 | 線程生成/線程銷燬 | 允許擴展 | StackOverflowError, OutOfMemoryError |
Java堆 | 對象實例 | 虛擬機啓動/虛擬機關閉 | 允許擴展 | OutOfMemoryError |
方法區(包括運行時常量池) | 已加載的類信息,靜態變量等(常量保存在運行時常量池中) | 虛擬機啓動/虛擬機關閉 | 允許擴展 | OutOfMemoryError |