1. 程式人生 > 實用技巧 >JVM虛擬機器(一)

JVM虛擬機器(一)

執行時的資料區域

Java虛擬機器在執行Java程式是會將所管理的記憶體分為若干個區域

轉載
方法區與堆區為執行緒共享資料區,虛擬機器棧,本地方法棧,程式計數器為執行緒私有。

程式計數器

程式計數器是一塊較小的記憶體空間。可以看做是當前執行緒所執行的位元組碼的行號指示器。位元組碼直譯器通過改變計數器的數值來選取下一條需要執行的位元組碼指令。多執行緒時,每個執行緒都有一個獨立的程式計數器,每個計數器之間互不影響。
如果執行緒正在執行一個Java方法,計數器記錄的是正在執行的虛擬機器位元組碼指令的地址。當執行本地方法時,計數器為空(Undefined)
它是程式控制流的指示器,分支,迴圈,跳轉,異常處理,執行緒恢復等

基礎功能都需要依賴這個計數器來完成

Java虛擬機器棧

生命週期和執行緒相同,虛擬機器棧描述的是Java方法執行的記憶體模型:每個方法被執行時,Java虛擬機器都會同步建立一個棧幀用於儲存區域性變量表,運算元棧,動態連結,方法出口等資訊。每一個方法被呼叫直至執行完畢的過程就對應著一個棧幀從虛擬機器棧入棧到出棧的過程。
區域性變量表存放了編譯期可知的各種Java虛擬機器基本資料型別(boolean,byte,char,short,int,float,long,double),物件引用(不等於物件本身,可能是一個指向物件起始地址的引用指標,也可能是一個代表物件的控制代碼或其他於此物件相關的位置),returnAddress(指向了一條位元組碼指令的地址)。

這些資料型別在區域性變量表中的儲存空間以區域性變數槽(slot)表示,其中64位的long和double型別的資料會佔用兩個變數槽,其餘只佔一個。
區域性變量表所需記憶體空間在編譯期完成分配,進入方法時分配的記憶體是確定的,執行期間不會改變區域性變量表的大小(大小指槽的數量)
如果執行緒請求的深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常,如果Java虛擬機器棧容量可動態擴充套件,當棧擴充套件時,無法申請到足夠的記憶體會丟擲OutMemoryError異常。

本地方法棧

虛擬機器棧為執行Java方法(位元組碼)服務,本地方法棧為虛擬機器執行本地方法服務。

Java堆

虛擬機器所管理記憶體最大的一塊,被所有執行緒所共享,在虛擬機器啟動是建立,此區域的唯一目的是存放物件例項。
從分配記憶體的角度看,Java堆可以劃分出多個執行緒私有的分配緩衝區(TLAB),以提升物件分配時的效率。
堆疊無法擴充套件時,虛擬機器會丟擲OutMemoryError異常。

方法區

執行緒共享區,用來儲存虛擬機器載入的型別資訊,常量,靜態變數,即時編譯器編譯後的程式碼快取等資料。
方法區無法滿足新的記憶體分配需求時,將丟擲OutOfMemoryError異常。

執行時常量池

執行時常量池是方法區的一部分,Class檔案中除了有類的版本,欄位,方法,介面等描述資訊外,還有常量資訊表,用於存放編譯期生成的各種字面量與符號引用,這部分內容將在類載入後存放到方法區的執行時常量池中。
常量池無法在申請到記憶體時會丟擲OutOfMemoryError異常。

直接記憶體

直接記憶體不是Java虛擬機器執行時資料區中的一部分。
JDK1.4 中新加入了NIO(New Input/Output)類,引入了基於通道與緩衝區的I/O方式,他可以使用Native函式庫直接分配對外記憶體,然後通過一個儲存在Java堆中的DirectByteBuffer物件作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著提高效能。