Java內存區域與內存溢出異常
Java虛擬機在執行Java程序的過程中會把它管理的內存分為不同的若干個數據區域。
具體的情況如下圖所示:

jvm
我們可以可到運行時數據區主要有以下幾個部分組成:
- 程序計數器(Program Counter Register)
- Java虛擬機棧(VM Stack)
- 本地方法棧(Native Method Stack)
- Java堆(Heap)
- 方法區
我們一個個看分析一下這些部分的功能和特點。
程序計數器(Program Count Register)
程序計數器是一塊比較小的內存區域,它的作用是:當前線程所助興的字節碼的符號顯示器。
這里有一個需要注意的地方,即【當前線程】,也就是說程序計數器是每個線程獨享的,它用于在線程切換后能恢復到上一次的正確執行位置。
這個區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
Java虛擬機棧
Java虛擬機棧也是線程私有的,它的生命周期與線程相同。
這一部分描述的是Java方法執行的內存模型:
每個方法被執行的時候都會創建一個棧幀(Stack Frame),用于存儲局部變量表等信息。每一個方法被調用直至執行完成的過程,就對應著一個棧幀從入棧到出棧的過程。
在虛擬機棧中最重要的部分是局部變量表, 存放了編譯期可知的基本數據類型,對象引用等等。
局部變量表所需的內存空間在編譯期完成分配。
這個區域可能拋出兩種異常:
- 如果線程請求的棧深度大于虛擬機所允許的深度: 拋出StackOverflowError
- 如果虛擬機棧可以動態擴展,當擴展無法申請到足夠內存時,拋出OutOfMemoryError
本地方法棧
本地方法棧與虛擬機棧基本一致,不同的是本地方法棧是位虛擬機使用到的Native方法服務的。在有些虛擬機中(Sun HotSpot),直接把本地方法棧和虛擬機棧合二為一了。
Java堆
我們嘗試總結Java堆的特性如下:
- Java堆是被所有線程共享的一塊內存區域
- 在虛擬機啟動時創建
- 這一區域的目的是:存放對象實例
- Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱為“GC堆”
- Java堆可以處于物理上不連續的內存空間,只要在邏輯上連續就行了
方法區
與Java堆一樣,方法區也是線程共享的內存區域。
它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等等。
垃圾收集行為在這個區域比較少見,回收目標主要是常量池的回收和對類型的卸載。
運行時常量池(Runtime Constant Pool)
運行時常量池是方法區的一部分,用于存放編譯器生成的各種字面量和符號引用。
運行時常量池具備動態性,運行期間也可以將新的常量放入池中。