標籤:靜態變數 nat 基礎 執行 串連 efi err 載入 收集器
Java虛擬機器記憶體劃分為以下幾個地區:
1、方法區:方法區是各個線程共用的記憶體地區,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的代碼等資料。雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它有一個別名叫做Non-Heap(非堆),目的是與Java堆分開來。
對於習慣在HotSpot虛擬機器上開發、部署的程式開發人員來說,很多人更願意把方法區稱為“永久代”,本質上兩者並不等價,僅僅是因為HotSpot虛擬機器的設計團隊選擇把GC分帶手機擴充至方法區,或者說使用永久代來實現方法區而已,這樣HotSpot的垃圾收集器可以像管理Java堆一樣管理這部分記憶體,能夠省區專門為方法區編寫記憶體管理代碼的工作。
Java虛擬機器規範對方法區的限制非常寬鬆,除了和Java堆一樣不需要連續的記憶體就可以選擇固定大小或者可擴充外,還可以選擇不實現垃圾收集。根據Java虛擬機器規範,當方法區無法滿足記憶體配置時將拋出OutOfMemoryError異常。
2、虛擬機器棧:Java虛擬機器棧也是線程私人的,其生命週期與線程相同,虛擬機器棧描述的是Java方法執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀用於儲存局部變數表、運算元棧、動態連結、方法出口等資訊。每個方法從調用到執行完成的過程,就對應一個棧幀在虛擬機器棧中入棧到出棧的過程。
局部變數表存放了編譯期克制的各種基礎資料型別 (Elementary Data Type)、對象引用。其中64位長度的long和double類型的資料類型會佔用2個局部變數空間,其餘的資料類型只佔用一個。局部變數表所需的記憶體空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多多大的局部變數空間是完全決定的,在方法運行期間不會改變局部變數表的大小。
在這個地區中有兩種異常情況:如果線程的請求的棧深度大於虛擬機器所允許的深度,將拋出StackOverflowError異常;如果虛擬機器棧可以動態擴充,如果擴充時無法申請到足夠的記憶體,就會拋出OutOfMemoryError。
3、本地方法棧:本地方法棧於虛擬機器棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機器棧為虛擬機器執行Java方法服務,而本地方法棧則為虛擬機器使用到的Native方法服務。在虛擬機器棧規範中對方法棧中方法使用的語言、使用方式與資料結構並沒有強制規定,因此具體的虛擬機器可以自由實現它。甚至有的虛擬機器(如HotSpot)直接把本地方法棧和虛擬機器棧合二為一,同虛擬機器棧一樣,本地方法棧也會拋StackOverflowError和OutOfMemoryError。
4、堆:Java堆是所有線程共用的一塊記憶體地區,在虛擬機器啟動時建立。此地區的目的是存放對象的執行個體,幾乎所有的對象執行個體都在這裡分配記憶體。Java堆是垃圾收集器管理的主要區域,因此有時候也稱為“GC堆”。從記憶體回收的角度來看,由於現在收集器基本都採用分代收集演算法,所以Java堆中還可以細分為:新生代和老年代;再細緻一點的有Eden空間、From、Survivor空間、To Survivor空間等。從記憶體配置的角度來看,線程共用的Java堆中可能劃分出多個線程私人的分配緩衝區。不過無論如何劃分,都與存放內容無關,無論哪個地區,儲存的都仍然是對象執行個體,進一步劃分的摸底是為了更好地回收記憶體,或者更快地分配記憶體。
Java堆可以是物理上不串連記憶體空間,只要邏輯上連續即可,就像我們的磁碟空間一樣。在實現時,既可以實現成固定大小的,也可以是可擴充的,不過當前主流的虛擬機器都是按照可擴充來實現的。如果堆中沒有記憶體完成執行個體分配,並且堆也無法再擴充時,將會拋出OutOfMemoryError。
5、程式計數器:是一塊較小的記憶體空間,可以看做是當前線程執行的位元組碼的行號指標。位元組碼解譯器工作時通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、線程恢複等基礎功能都依賴這個計數器來完成。為了確保多線程切換後能夠恢複到正確的位置,每一條線程都有一個獨立的程式計數器,各個線程間的程式計數器互不影響,隔離儲存區 (Isolated Storage),為線程私人的記憶體。如果線程執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令地址;如果真在執行的是Native方法,這個計數器值則為空白(Undefined)。此記憶體地區是Java虛擬機器規範中唯一一個沒有規定任何OutOfMemoryError情況的地區。
Java虛擬機器學習-Java記憶體地區(一)