運行時數據區域java
Java虛擬機在執行Java程序過程當中把所管理的內存劃分爲如下幾個不容的數據區域,這些區域都有各自的用途,以及建立時間和銷燬時間。
程序員
程序計數器、虛擬機棧、堆、方法區、本地方法棧算法
程序計數器數組
背景:java 多線程是經過線程輪流切換並分配處理執行時間來實現,在任何一個時刻,一個處理器只會執行一條線程的指令。所以須要用一塊內存空間記錄線程的執行狀態,這就是程序計數器。多線程
存儲的內容:存放程序下一條指令的地址地方。佈局
目的:爲了線程切換後可以恢復到正確的執行位置,每條線程都有一個獨立的程序計數器。(惟一一個沒有沒有OutOfMemeryEror狀況的區域)。「記錄現場,恢復現場」spa
java虛擬機棧線程
存放內容:局部變量表、操做數棧、動態連接、方法出口(線程私有,生命週期與線程相同。)指針
虛擬機棧:是Java方法執行的內存模型。每一個方法在執行的同時都會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口。orm
生命週期:每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中的的入棧到出棧過程
局部變量表存放了編譯期可知的各類基本數據類型、對象引用和returnAdderss類型
當進入一個方法時,這個方法所須要在幀中分配多大的局部變量空間是徹底肯定的。方法運行期間不會改變局部變量表的大小
Java虛擬機規範中對這個區域定義了兩種異常情況:StackOverflowError(線程請求棧深度 > 虛擬機所容許的深度)。OutOfMemoryError(若是Java虛擬機動態擴展沒法申請足夠內存的時候)
本地方法棧
與虛擬機棧一致,惟一區別虛擬機棧爲 java 方法服務。本地方法棧是爲 native 方法服務。
Java 堆
目的:惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配。
Java 堆是Java虛擬機所管理的內存中最大的一塊。
Java堆是被全部線程共享的一塊內存區域,在虛擬機啓動的時候建立。
Java 堆是垃圾回收器管理的主要區域,所以也被稱爲「GC堆」(垃圾堆)。
分類:因爲如今垃圾收集器基本採用分代收集算法,因此Java堆中還能夠分爲:新生代,老年代;再細緻一點還有 Eden空間、From Survivor 空間、 To Survivor空間。
根據Java虛擬機規範,Java堆能夠處於物理上不連續的內存空間中,只要邏輯連續便可
若是堆中沒有內存完成分配實例,而且堆也沒法擴展,將會拋出OutOfMemory異常
方法區
存儲對象:它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼。方法區也被稱爲永久帶
與Java堆同樣,是各個線程的共享的內存區域。
深刻探討Hotspot虛擬機在Java堆中的對象分佈,佈局和訪問的過程
對象的建立
虛擬機遇到 new 指令時候,首先檢查指令的參數是否能在常量池中定位到一個類的符號引用,並檢查這個符號引用表明的類是否已經被加載、解析、初始化。若是沒有,那必須執行相應的類加載過程
在類加載經過後,虛擬機將爲新生對象分配內存。對象所需內存的大小在類加載完成後即可以徹底肯定。
Java 堆爲對象分類內存的兩種方式
指針碰撞:假設java堆是絕對規整的,全部用過的內存放在一邊,空閒的內存放在另外一邊,中間放着一個指針做爲分界點的指示器,分配內存就僅僅是把指針向空閒空間那邊挪動一段與對象大小相等的距離
空閒列表:若是Java 堆並非規整的,已使用的內存和空閒內存相互交錯,虛擬機就必須維護一個列表,記錄哪些內存塊是可用的。
選擇哪一種方式取決於Java堆是否規整,而Java堆是否規整又取決於垃圾收集器是否帶有壓縮整理功能決定。
內存分配完成後,虛擬機須要將分配到的內存空間都初始化爲零值
虛擬機對對象進行必要設置,例如找個對象是哪一個類的實例,如何才能找到類的元數據信息,對象的哈希碼、對象的GC分代年齡。這些信息都存放在對象的對象頭中。
從虛擬機視角來看,一個新的對象已經產生,但從Java程序視角來看,對象建立纔剛剛開始--<init>方法尚未執行。全部字段都仍是零。執行new指令以後會接着執行<init>方法,把對象按照程序員的意願進行初始化。這樣一個真正的對象纔算徹底產生。
總結:JVM遇到new指令 —> 檢查指令參數,與常量池中類符號引用匹配 & 檢查類是否被加載 —> Java 堆爲對象分配內存(分配內存兩種方式)—> 內存空間初始化爲零 & 對對象進行必要設置—> 執行init方法
對象的內存分佈
對象在內存中存儲的佈局能夠分爲3個區域:對象頭,實例數據,對齊填充
對象頭:包含用於存儲對象自身的運行時數據,類型指針
自身運行時數據:HashCode 哈希碼、GC分代年齡、鎖狀態標識、線程持有的鎖、偏向線程ID、偏向時間戳。
類型指針:對象指向它的類元數據的指針。若是對象是一個Java數組,那麼對象頭中還必須存儲數組長度。
實例數據:對象真正存儲的有效信息,也是程序代碼中所定義的各類類型的字段內容。
對齊填充:僅僅起佔位符的做用。HotSpot VM 的自動內存管理系統的要求對象起始地址必須是8的整數倍,也就是說對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的整數倍。因此對象實例部分沒有對齊時,就須要經過對齊填充來補全。
對象的定位訪問
產生背景:Java 程序須要經過棧上的reference數據來操做堆上的具體對象。因爲reference類型在Java虛擬機規範中只規定了一個指向對象的引用,並沒有定義這個引用該經過何種方式去定位、訪問堆中的對象的具體位置。
定位方式:句柄、直接指針。
句柄:Java堆中將會劃分出一塊內存做爲句柄池,reference 中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。