運行時數據區主要包括:方法區,堆,Java 虛擬機棧,程序計數器,本地方法棧。java
其中方法區和堆全部線程共享,Java棧,程序計數器,本地方法棧線程私有。算法
一塊較小的內存空間,能夠看作是當前線程所執行的字節碼行號的指示器;多線程
字節碼解釋器工做時,經過改變計數器的值 選取下一條執行的字節碼指令;(一些基本功能都須要依賴計數器來完成如:分支、循環、跳轉、異常處理、線程恢復等)this
Java 虛擬機多線程是經過線程間輪流切換來分配給處理器執行時間;在肯定時間節點,一個處理器(一核)只會執行一個線程的指令。spa
爲保證線程切換回來後能恢復到原執行位置,各個線程間計數器互相不影響,獨立存儲(稱之爲線程私有的內存)。線程
當線程正執行 Java 程序時:程序計數器 記錄正在執行的虛擬機字節指令地址。code
執行 native
方法,計數器值爲空 undefined
;cdn
該內存區域是惟一一個 Java 虛擬機規範中沒有規定任何 OutOfMemoryError
狀況的內存區域;對象
這塊內存區域是線程私有的。blog
虛擬機棧是方法的工做空間,由一個一個的棧幀組成,棧幀是在每個方法調用時產生的。
每個棧幀由局部變量區
、操做數棧
等組成。每建立一個棧幀壓棧,當一個方法執行完畢以後則出棧。
- 若是出現方法遞歸調用出現死循環的話就會形成棧幀過多,最終會拋出
StackOverflowError
。- 若線程執行過程當中棧幀大小超出虛擬機棧限制,則會拋出
StackOverFlowError
。- 若虛擬機棧容許動態擴展,但在嘗試擴展時內存不足,或者在爲一個新線程初始化新的虛擬機棧時申請不到足夠的內存,則會拋出
OutOfMemoryError
。
這塊內存區域也是線程私有的。
Java 堆是整個虛擬機所管理的最大內存區域,全部的對象建立都是在這個區域進行內存分配。
堆區包括屬性空間和方法空間,屬性的類型決定開闢空間大小,屬性個數決定開闢空間數量,堆中存放方法引用的空間大小爲4個字節
這塊區域也是垃圾回收器重點管理的區域,因爲大多數垃圾回收器都採用分代回收算法
,全部堆內存也分爲 新生代(Young)
、老年代(Old)
,能夠方便垃圾的準確回收。
新生代 ( Young ) 又被劃分爲三個區域:Eden、From Survivor、To Survivor。
新生代:Young Generation
,主要用來存放新生的對象。
老年代:Old Generation
或者稱做 Tenured Generation
,主要存放應用程序聲明週期長的內存對象。
這塊內存屬於線程共享區域。
在 Sun JDK 中這塊區域對應的爲 PermanetGeneration ,又稱爲持久代,方法區是堆的邏輯部分。
方法區主要用於存放已經被虛擬機加載的類信息,如常量
,靜態變量
。 這塊區域也被稱爲永久代
。
因爲持久代內可能會發生內存泄露或溢出等問題而致使的 java.lang.OutOfMemoryError: PermGen
,JEP小組從 JDK1.7
開始就籌劃移除持久代(JEP 122: Remove the Permanent Generation),而且在 JDK 1.7
中把字符串常量,符號引用等移出了持久代。到了 Java 8
,持久代被完全地移出了 JVM
,取而代之的是元空間(Metaspace
):
In JDK 8, classes metadata is now stored in the native heap and this space is called Metaspace.
因此從Java 8開始,方法區被移至 Metaspace 內。
這塊內存屬於線程共享區域。
運行時常量池是class文件中每個類或接口的常量池表的運行時表示形式,是方法區的一部分。
它包括了若干種不一樣的常量。常量池表存放編譯器生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常量池中存放。運行時常量池具備動態性,運行期間也能夠將新的量放到運行時常量池中,典型的應用是String類的intern方法:
public native String intern() 複製代碼
JDK 1.7
開始,字符串常量和符號引用等就被移出持久代
:
Native Heap
)Java Heap
)