Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域。這些區域都有各自的用途,以及建立和銷燬的時間,有的區域隨着虛擬機進程啓動而存在,有些區域則依賴用戶線程的啓動和結束位創建和銷燬,根據《Java虛擬機規範》,Java虛擬機將會包含如下幾個運行時數據區域:java
(圖片來源於網絡)網絡
程序計數器(Progeam Counter Register)是一塊較小的內存空間,能夠當作當前程序所執行的字節碼的行號指示器;數據結構
因爲Java虛擬機多線程是經過線程輪流切換並分配處理執行時間的方式來實現的,須要在切換後線程間的程序計數器互不影響,因此線程計數器是線程私有的;多線程
若是線程正在執行的是一個Java方法,計數器記錄的是正在執行的虛擬機字節碼指令的地址,若是正在執行的是Native方法,計數器爲空;spa
此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域線程
Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行的同時會建立一個棧幀(Srack Frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。指針
常常咱們把Java內存分爲堆內存(Heap)和棧內存(Stack),這種分發比較粗糙的,一般是棧內存只是Java虛擬機棧的局部變量部分。對象
局部變量表存放了編譯期可知的各類基本數據類型(boolean、byte、char、short、int、float、long、double)以及對象的引用(reference類型,多是一個指向對象其實地址的引用指針,也多是指向一個表明對象的句柄或其餘與此對象有關的位置)和returnAddress類型(指向了一個一條字節碼指令的地址);其中64位長度的long和double類型的數據佔用2個局部變量空間(Slot),其他數據類型只佔1個空間。局部變量表所需內存給空間在編譯期分配,在方法運行期間不會改變大小。接口
異常:StackOverflowError當棧深度大於容許的深度時拋出;OutOfMemoryError當擴展時沒法申請到足夠的內存時拋出生命週期
本地方法棧(Native Method Stack),與虛擬機棧功能相似,只是,本地方法棧只用於Native方法服務,而虛擬機棧用於Java方法服務。虛擬機規範中沒有對本地方法棧中使用語言和數據結構作強制規定。因此存在如Sun HotSpot虛擬機這樣直接把本地方法棧和虛擬機棧合二爲一的。
Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊,被全部線程共享,在虛擬機啓動時建立
Java堆是垃圾收集器管理的主要區域,所以不少時候也被叫作「GC堆"
根據Java虛擬機規範的規定,Java堆能夠處於物理上不連續的內存空間中,只要邏輯上連續便可
當堆中內存不足,且沒法再擴展時,將會拋出OutOfMemoryError異常
方法區(Method Area)與Java堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
在Java虛擬機規範中對方法區的限制很是寬鬆,除了和Java堆同樣不須要連續的內存和能夠選擇固定大小或者可擴展外,還能夠選擇不實現垃圾回收。這個區域的內存回收主要目標是針對常量池的回收和對類型的卸載,這個區域的垃圾回收如今還比較難使人滿意,主要是類型的卸載,條件至關的苛刻。
JDK1.7之前Sun HotSpot將GC分代收集擴展到了方法區,省去了專門爲方法區編寫內存管理代碼的工做,但這樣更容易形成內存溢出,因此在JDK1.7中,HotSpot已經把本來放在永久代中的字符串常量池移出。
Java虛擬機規範規定,當沒法知足內存分配需求是,將拋出OutOfMemoryError異常。
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯期生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時存放。
Java虛擬機對Class文件每一部分的格式都有嚴格規定,每個字節用於存儲哪一種數據都必須符合規範上的要求才會被虛擬機承認、裝載和執行,但對運行時常量池,沒有作怎麼細節的要求。
運行時常量池具備動態性,即運行期也能夠將新的常量放入池中。
一樣有OutOfMemoryError異常
直接內存並不屬於java虛擬機規範中指定的內存區域,可是這部份內存也被頻繁的使用,並且也可能會致使OutOfMemoryError異常出現。
最多見使用直接內存的地方時JDK1.4之後加入的NIO的DirectByteBuffer,直接使用系統內存,這樣能夠避免數據在本地方法棧和java虛擬機棧來回拷貝,即從java虛擬機棧內存拷貝到系統內存。