Java記憶體區域包含程式計數器、虛擬機棧、本地方法棧、Java堆、方法區五個區域。 運行時數據區分類 Java記憶體區域 一、程式計數器 程式計數器(Program Counter Register)是一塊較小的記憶體空間,它可以看作是當前線程所執行的位元組碼的信號指示器。 位元組碼解釋器工作時就是通過改變 ...
Java記憶體區域包含程式計數器、虛擬機棧、本地方法棧、Java堆、方法區五個區域。
運行時數據區分類
Java記憶體區域
一、程式計數器
程式計數器(Program Counter Register)是一塊較小的記憶體空間,它可以看作是當前線程所執行的位元組碼的信號指示器。
位元組碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。由於Java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器(對於多核處理器來說是一個內核)都只會執行一條線程中的指令。因此,為了線程切換後能恢復到正確的執行位置,每條線程都需要有一個獨立的程式計數器,各條線程之間計數器互不影響,獨立存儲,我們稱這類記憶體區域為“線程私有”的記憶體。如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機位元組碼指令的地址;如果正在執行的是Native方法,這個計數器值則為空(Undefined)。
二、Java虛擬機棧
Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。虛擬機棧描述的是Java方法執行的記憶體模型:每個方法在執行的同時都會創建一個棧幀(Stack Frame)用於存儲局部變數表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。
- 局部變數表
局部變數表存放了編譯器可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型,它不等同於對象本身,可能是一個指向對象起始地址的引用指針,也可能是指向一個代表對象的句柄或其他與此對象相關的位置)和returnAddress類型(指向了一條位元組碼指令的地址)。
可能的異常
在Java虛擬機規範中,對這個區域規定了兩種異常狀況:如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常;如果虛擬機棧可以動態擴展(當前大部分的Java虛擬機都可動態擴展,只不過Java虛擬機規範中也允許固定長度的虛擬機棧),如果擴展時無法申請到足夠的記憶體,就會拋出OutOfMemoryError異常。
三、本地方法棧
本地方法棧(Native Method Stack)與虛擬機棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧為虛擬機執行Java方法(也就是位元組碼)服務,而本地方法棧則為虛擬機使用到的Native方法服務。
四、 Java堆
Java堆(Java Heap)是Java虛擬機所管理的記憶體中最大的一塊。Java堆是被所有線程共用的一塊記憶體區域,在虛擬機啟動時創建。所有的對象實例以及數組都要在堆上分配。
可能的異常
如果在堆中沒有記憶體完成實例分配,並且堆也無法再擴展時,將會拋出OutOfMemoryError異常。
五、方法區
方法區(Method Area)與Java堆一樣,是各個線程共用的記憶體區域,它用於存儲已被虛擬機載入的類信息、常量、靜態變數、即時編譯器編譯後的代碼等數據。
對於習慣在HotSpot虛擬機上開發、部署程式的開發者來說,很多人都更願意把方法區稱為“永久代”(Permanent Generation),本質上兩者並不等價,使用永久代來實現方法區,現在看來並不是一個好主意,因為這樣更容易遇到記憶體溢出問題(永久代有-XX:MaxPermSize的上限),而且有極少數方法(例如String.intern())會因這個原因導致不同虛擬機下有不同的表現。現在也有放棄永久代並逐步改為採用Native Memory來實現方法區的規划了。
- 運行時常量池
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、欄位、方法、介面等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯器生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的運行時常量池中存放。
六、直接記憶體
直接記憶體(Direct Memory)並不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的記憶體區域。但是這部分記憶體也被頻繁地使用,而且也可能導致OutOfMemoryError異常出現,所以我們放到這裡一起講解。
可能的異常
本機直接記憶體的分配不會受到Java堆大小的限制,但是,既然是記憶體,肯定還是會受到本機總記憶體(包括RAM以及SWAP區或者分頁文件)大小以及處理器定址空間的限制。伺服器管理員在配置虛擬機參數時,會根據實際記憶體設置-Xmx等參數信息,但經常忽略直接記憶體,使得各個記憶體區域總和大於物理記憶體限制(包括物理的和操作系統級的限制),從而導致動態擴展時出現OutOfMemoryError異常。