java虛擬機器記憶體分佈
概括
java虛擬機器在執行的時候,會把記憶體劃分成若干個記憶體塊、這些區域各自有各自的作用用途 。
1.程式計數器
程式計數器是一塊比較小的記憶體區域,它可以看做是當前執行緒所執行的位元組碼的行號指示器。位元組碼指示器工作的時候就是通過這個指令來獲取下一條需要執行的指令。(分支,迴圈,判斷、異常等都需要這個計數器來完成)
執行緒之間的指令是互不幹影響的。通常稱之為“執行緒私有”的記憶體
2.java虛擬機器棧
和程式計數器一樣,java虛擬機器棧也是執行緒私有的。它的生命週期和執行緒一樣。它描述的是java方法執行的記憶體模型。
每個方法在執行的時候都會建立一個棧幀,意味著每個方法從呼叫到執行完成都對應著一次入棧和出棧的過程。
儲存基本型別,物件引用,返回地址型別
如果執行緒請求的棧的深度大於虛擬機器的鎖允許的深度。將會丟擲stackoverflowError。
如果虛擬機器可以支援動態的擴容,如果申請時失敗,將會丟擲outofMemoryError異常
3.本地方法棧
本地方法棧和java虛擬機器棧極其類似,只是本地方法使用到的是native方法服務。有的虛擬機器(比如sun hotspot)直接將本地方法棧和java虛擬機器合二為一。
和java虛擬機器方法一樣也會丟擲stackoverflowError和 outofMemoryError異常
4.java堆
對於大多java應用來說,java堆是java記憶體中使用最大的一塊。java堆是所有執行緒共享的一塊區域。主管區域唯一的目的就是存放java物件的例項和java陣列。
隨著JIT編譯器的發展和逃逸分析技術。java虛擬機器規範中也明確提出所有的物件都在java對中分配已經不是那麼“絕對”了;
java堆是java垃圾回收主要的區域。因此很多時候也被稱之為“GC堆”。從記憶體回收的角度來看,由於現在主流的基本都採用分代收集演算法,所以java堆中還可以分為
新生代和老年代。在細緻一點有:eden空間,from survivor和to survivor等空間。
根據java虛擬機器規範:物理上java堆是可以不連續的、只要邏輯上連續既可。一般可以通過-Xmx 和 -Xms來控制。
如果堆中沒有記憶體分配例項並且堆也無法在擴充套件、將會丟擲OutofMemoryError異常。
5方法區
方法去和java對一樣是執行緒共享區域。它用於儲存已經被虛擬機器載入的類資訊。常量,靜態變數,等資料。雖然java虛擬機器把方法區描述為java堆的一個邏輯分割槽。
但是它卻有一個名稱(非堆)。
對於hotspot來說(其它的虛擬機器不存在永久區這個概念),很多人都願意把方法區稱之為永久代.因為hotspot使用永久帶來實現了方法區。這樣垃圾回收就可以像
管理java堆一樣來管理該區域。
但是使用永久代容易造成記憶體溢位(-XX:MaxpermSize限制)
6.執行時常量池
執行時常量是方法去的一部分。class檔案除了有類的版本,欄位,方法,介面等描述,還有一項資訊是常量池。用於存放編譯期生成的各種字面常量和符號引用。這部分
內容將在類載入後進入方法區的執行期常量存放。
7直接記憶體
直接記憶體並不屬於java虛擬機器執行時的一部分。也不是java虛擬機器規範中定義的區域。
在java1.4之後的NIO中,引入了通道和緩衝區的概念。它可以使用native函式庫直接分配堆外記憶體。然後通過一個儲存在java堆中的DirectByteBuffer對這塊記憶體
操作。這樣可以讓引用在一些場景中效能得到提升。避免了java堆和native中來回的複製資料。