Java運行時數據區域

運行時數據區域
Java虛擬機在執行Java程序的過程當中會把它管理的內存劃分爲若干個不一樣的數據區域。這些區域都有各自的用途,以及建立和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在, 有些區域則是依賴用戶線程的啓動和結束而創建和銷燬。如圖
1.1 程序計數器
是一塊內存比較小的空間。做用:用來標誌當前線程所執行的字節碼的行號指示器(即在字節碼中添加編號)。在jvm中,字節碼解釋器工做時就是經過改變這個計數器上的值來選取下一條須要執行的字節碼指令。在分支、循環、跳轉、異常處理、線程恢復等功能都須要依賴計數器去完成。在多線程中, 各條線程之間的計數器互不影響,獨立存儲。
不會存在OutOfMemoryError狀況的區域。
1.2 Java虛擬機棧
Java虛擬機棧也是線程私有的, 生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每一個方法被執行的時候都會建立一個棧幀用於存儲局部變量表、操做數棧、動態鏈接、方法出口等,而且每一個方法被調用直至執行完成的過程就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。
先理解什麼是棧幀:是用於支持虛擬機進行方法調用和方法執行的數據結構。棧幀是基於虛擬機棧上的,一個虛擬機棧存儲了多個棧幀,每一個棧幀記錄Java方法中局部標量表、操做數棧等信息同時也記錄該方法從入棧到出棧的過程。存儲結構如圖
在編譯程序代碼的時候,棧幀中須要多大的局部變量表,多深的操做數棧都已經徹底肯定,而且寫入到方法表的Code屬性之中,所以一個棧幀須要分配多少內存,不會受到程序運行期變量數據的影響,而僅僅取決於具體的虛擬機實現。
局部變量表: 是一組變量值的存儲空間,用於存放方法參數、局部變量和對象引用類型。在編譯程序代碼後就肯定須要局部變量的最大容量。變量槽是局部變量表中的最小單位。一個solt能夠存放(x32)boolean、byte、char、short、int、float、reference 和 returnAddress(執行字節碼指令的地址);對於64位的long和double變量則須要分配兩個連續的slot空間。爲了節省棧空間Slot是能夠重用的。不過有時也會影響垃圾回收行爲。
圖一
圖二
從圖一和圖二中能夠看出,圖二中變量槽是能夠重用的,變量a複用了placeholder的slot,致使placheholder的引用被刪除,內存被回收。
操做數棧常稱爲操做棧是一個後入先出棧。其最大的棧深度也在編譯過程當中就肯定了並保存在Class文件的Code屬性中。應用場景:在方法進行參數傳遞的時候是經過操做數棧進行的。 在概念模型中,兩個棧幀做爲虛擬機棧的元素, 相互之間是徹底獨立的, 可是大多數虛擬機的實現裏都會作些優化處理,使得兩個棧幀出現一部分重疊。讓下棧幀的部分操做與上面棧幀的部分局部變量表重疊在一塊兒,這樣在進行方法調用返回時就能夠共用一分部數據,而無需進行額外的參數複製傳遞了。
動態鏈接:每一個棧幀都包含一個執行運行時常量池中該棧幀所屬方法的引用,持有這個引用是爲了支持方法調用過程當中的動態鏈接。Class文件中存放了大量的符號引用,字節碼中的方法調用執行就是以常量池中指向方法的符號引用做爲參數。這些符號引用一部分會在類加載階段或第一次使用時轉化爲直接引用,這種轉化稱爲靜態解析。另外一部分將在每一次運行期間轉化爲直接引用,這部分稱爲動態鏈接。
方法出口:方法出口分爲兩種, 一種收到返回命令,正常退出;第二種執行遇到異常致使方法退出。
  
虛擬機棧會出現兩種異常:StackOverflowError和OutOfMemoryError
1.3 本地方法棧
本地方法棧與虛擬機棧做用很是類似,其區別不過是虛擬機棧爲執行Java方法(字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native方法服務。
Native方法:並不必定指Java中用native方法(如String.intern() :native方法),也包括其餘庫或者其餘語言中的方法如C、C++。
本地方法棧也會出現兩種異常:StackOverflowError和OutOfMemoryError
1.4 Java堆
Java堆是Java虛擬機所管理的內存中最大的一塊。是被全部線程共享的一塊內存區域,虛擬機啓動時建立。此內存區域的惟一目的就是存放對象實例。幾乎全部的對象實例都在這裏分配內存,但隨着jit編譯器的發展會有微妙的變化。
Java heap 是垃圾收集器管理的主要區域。在Java中,堆被劃分紅兩個不一樣的區域:新生代(Young)和老年代(Old)。新生代又被劃分爲三個區域:Eden空間、From Survivor空間、To Survivor空間。這樣劃分的目的是爲了更好地管理內存中的對象,包括內存的分配以及回收。堆的內存模型如圖(jdk1.6)
從圖中能夠看出:堆大小=新生代+老年代。其中堆大小能夠經過參數-Xms、-Xmx來設置。
Java 堆會有OutOfMemoryError異常
1.5 方法區
方法區與Java堆同樣,是各個線程共享的內存區域,可是存儲的內容不一樣。方法區用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯後的代碼等數據。別名Non-Heap. 另外方法區並非連續的,因此垃圾收集行爲在這個區域是不多出現的。
方法區還包括一部分:常量池。常量池是用於存放編譯器生成的各類字面量和符號引用,這部份內容將在類加載後存放到方法區的運行時常量池中。大小能夠經過-XX:PermSize和-XX:MaxPermSize設置。
方法區會有OutOfMemoryError異常
總結:
一、區分下java棧、java堆和方法區分別存儲內容:
public class Demo{
private String name ;
public Demo(String name){
this.name = name;
}
public static void main(String[] args){
Demo d = new Demo("test");
}
}
java堆          方法區         java棧
new Demo()     Demo類信息    Demo d、局部變量name
    Demo中的方法名   調用main方法主線程調用棧
相關文章
相關標籤/搜索