JVM在運行Java代碼時,會把內存分爲幾個模塊即數據區來使用,數據區的內容以下圖所示:html
1. PC寄存器:java
JVM支持程序多線程執行。而操做系統的任務調度採用的是時間片輪詢的搶佔式調度方式,也就是說,某一個肯定的時刻,一個處理器只能處理一條線程中的指令。所以,線程切換後如何恢復到原來正確的位置,即是經過每一個線程各自的寄存器來實現的。在各線程中寄存器獨立,互不干擾。
若是線程執行的方法不是native的,那PC寄存器保存的就是Java虛擬機正在執行的字節碼指令的地址,若是該方法是native的,那寄存器的值就是undefined(null),此內存區域是惟一一個在JAVA虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。算法
2. JAVA虛擬機棧:
java虛擬機棧也是Java線程私有的,它的生命週期與線程同樣,用於存儲棧幀,主要包括兩部分,方法中的局部變量和方法執行過程當中產生的中間結果。每個方法從調用直到執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。多線程
由於除了棧幀的出棧和入棧以外,Java 虛擬機棧不會再受其餘因素的影響,因此棧幀能夠在堆中分配,Java 虛擬機棧所使用的內存不須要保證是連續的。oracle
JVM規範容許VM Stack要麼是一個固定大小,要麼動態擴展來知足要求。若是JVM棧是一個固定的大小,當棧被建立的時候每個棧大小能夠自由設置。而在動態擴展狀況下,能夠控制最大或最小內存;spa
Java虛擬機棧可能會發生以下異常狀況:操作系統
3. Java堆
對於大多數應用來講,堆是Java虛擬機所管理的內存中最大的一塊。堆是可供全部線程共享的一塊內存區域,是在虛擬機啓動的時候建立的。它惟一的目的就是存儲對象實例,幾乎全部的對象實例都在這裏分配內存。
Java堆是垃圾回收器管理的主要區域,不少時候也被翻譯爲GC堆。而從內存分配的角度來看,因爲如今收集器基本都採用分代收集算法,因此Java堆還能夠細分爲:新生代,老年代,永久代等等。
Java堆的容量能夠是固定大小的,也能夠根據需求動態擴展,而且Java堆能夠處於物理上不連續的內存空間中。只要邏輯上是連續的便可,就像咱們的磁盤空間同樣。
堆中可能會發生的異常:線程
4. 方法區
方法區與堆同樣,是各個線程共享的內存區域,存儲了每個類的結構信息,如運行時常量池,靜態變量,常量,構造方法和普通方法的字節碼內容等等;方法區也是在虛擬機啓動的時候被建立。
JVM規範堆方法區的限制很是寬鬆,它能夠做爲堆的一個邏輯組成部分,擁有和堆大部分相同的性質,如能夠選擇固定大小和可擴展,也能夠選擇不實現垃圾回收。
一樣,當方法區沒法知足內存分配需求時,會拋出OutOfMemoryError異常;翻譯
5. 運行時常量池
首先,運行時常量池位於方法區內,屬於方法區的一部分。存放的是編譯期生成的各類字面量和符號引用。在類和接口被加載到虛擬機後,對應的運行時常量池就被建立出來。。
在建立類和接口的運行時常量池時,可能會發生以下異常狀況:htm
6. 本地方法棧
本地方法棧與虛擬機棧所發揮的做用是很是類似的,它們的區別不過是虛擬機棧爲虛擬機執行Java方法服務,而本地方法棧則爲虛擬機使用到的Native方法服務。因此說,當虛擬機使用到其餘語言的時候,就會使用到本地方法棧。
而若是Java虛擬機不支持native方法,而且本身也不依賴傳統棧的話,能夠無需支持本地方法棧。若是支持本地方法棧,那這個棧通常會在線程建立的時候按線程分配。
本地方法棧和虛擬機棧性質相似,能夠固定大小,也能夠動態擴展,異常拋出也同樣。
https://docs.oracle.com/javase/specs/index.html
參考自:《深刻理解JAVA虛擬機》