根據《Java虛擬機規範(Java SE 7版)》的規定,Java虛擬機所管理的內存將會包括如下幾個運行時數據區域:
算法
程序計數器(Program Counter Register)是一塊較小的內存空間,它能夠看做是當前線
程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各類虛擬機可能
會經過一些更高效的方式去實現),字節碼解釋器工做時就是經過改變這個計數器的值來選
取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需
要依賴這個計數器來完成。數組
因爲Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式來實現的,
在任何一個肯定的時刻,一個處理器(對於多核處理器來講是一個內核)都只會執行一條線
程中的指令。所以,爲了線程切換後能恢復到正確的執行位置,每條線程都須要有一個獨立
的程序計數器,各條線程之間計數器互不影響,獨立存儲,咱們稱這類內存區域爲「線程私
有」的內存。markdown
若是線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指
令的地址;若是正在執行的是Native方法,這個計數器值則爲空(Undefined)。此內存區域
是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。多線程
與程序計數器同樣,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的
生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行的同時
都會建立一個棧幀(Stack Frame [1] )用於存儲局部變量表、操做數棧、動態連接、方法出口
等信息。每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出
棧的過程。優化
常常有人把Java內存區分爲堆內存(Heap)和棧內存(Stack),其中棧就是指虛擬機棧.
其中64位長度的long和double類型的數據會佔用2個局部變量空間(Slot),其他的數據
類型只佔用1個。spa
在Java虛擬機規範中,對這個區域規定了兩種異常情況:若是線程請求的棧深度大於虛
擬機所容許的深度,將拋出StackOverflowError異常;若是虛擬機棧能夠動態擴展(當前大部
分的Java虛擬機均可動態擴展,只不過Java虛擬機規範中也容許固定長度的虛擬機棧),如
果擴展時沒法申請到足夠的內存,就會拋出OutOfMemoryError異常.線程
本地方法棧(Native Method Stack)與虛擬機棧所發揮的做用是很是類似的,它們之間
的區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則爲虛
擬機使用到的Native方法服務。與虛擬機棧同樣,本地方法棧區域也會拋出StackOverflowError
和OutOfMemoryError異常。指針
Java堆是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。此內存區域的惟一目的就
是存放對象實例,幾乎全部的對象實例都在這裏分配內存。這一點在Java虛擬機規範中的描
述是:全部的對象實例以及數組都要在堆上分配 [1] ,可是隨着JIT編譯器的發展與逃逸分析技
術逐漸成熟,棧上分配、標量替換 [2] 優化技術將會致使一些微妙的變化發生,全部的對象都
分配在堆上也漸漸變得不是那麼「絕對」了。code
Java堆是垃圾收集器管理的主要區域,所以不少時候也被稱作「GC堆」從內存回收的角度來看,因爲如今收集器基本都採用分代收集算法,因此Java堆中還能夠細分爲:新生代和老年代;再細緻一點的有Eden空間、From Survivor空間、To Survivor空間等。若是在堆中沒有內存完成實例分配,而且堆也沒法再擴展時,將會拋出OutOfMemoryError異常。對象
*註釋 對象實例數據指的是在 Java 中建立的各類實例對象以及它們的值
方法區(Method Area)與Java堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。它有一個別名叫作Non-Heap(非堆).根據Java虛擬機規範的規定,當方法區沒法知足內存分配需求時,將拋出OutOfMemoryError異常。這區域的內存回收目標主要是針對常量池的回收和對類型的卸載
*註釋 對象類型數據指的是定義在 Java 代碼中的常量、靜態變量、以及在類中聲明的各類方法、方法字段等等;同事可能包括即時編譯器編譯後產生的代碼數據。
運行時常量池
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、
字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於
存放編譯期生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常
量池中存放。
在Java程序中,有不少的東西是永恆的,不會在運行過程當中變化。好比一個類的名字,一個類字段的名字/所屬類型,一個類方法的名字/返回類型/參數名與所屬類型,一個常量,還有在程序中出現的大量的字面值。
好比下面小段源碼中粗體代碼顯示的部分:
public class ClassTest { private String itemS ="咱們 "; private final int itemI =100 ; public void setItemS (String para ){...} }
直接內存
直接內存(Direct Memory)並非虛擬機運行時數據區的一部分,也不是Java虛擬機規
範中定義的內存區域。本機直接內存的分配不會受到Java堆大小的限制
經過句柄訪問對象:
經過直接指針訪問對象: