JVM 內(nèi)存模型

1、程序計數(shù)器/PC寄存器(the PC Register)

? ? ? 程序計數(shù)器 -- 用于指定字節(jié)碼解析器嚇一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。

? ? ? Java 虛擬機可以同時支持多個執(zhí)行線程 。每個 Java 虛擬機線程都有自己的 pc (程序計數(shù)器) 寄存器。在任何時候, 每個 Java 虛擬機線程都在執(zhí)行單個方法的代碼, 即該線程的當(dāng)前方法。如果該方法不是本機方法, 則 pc 寄存器包含當(dāng)前正在執(zhí)行的 Java 虛擬機指令的地址。如果線程當(dāng)前執(zhí)行的方法是本機的, 則 Java 虛擬機的 pc 寄存器的值是未定義的(undefined)。Java 虛擬機的 pc 寄存器足夠?qū)? 可以在特定平臺上保存返回地址或本機指針。

2、Java 虛擬機棧(Java Virtual Machine Stacks)

? ? ? ? Java 虛擬機棧與程序計數(shù)器一樣,Java 虛擬機棧也是線程私有的,它與線程的生命周期是一致的。每個Java虛擬機線程都有一個自己私有的Java 虛擬機棧,該虛擬機棧在線程創(chuàng)建的同時被創(chuàng)建。Java 虛擬機棧類似于傳統(tǒng)的語言(例如C語言)的棧。它包含局部變量和部分結(jié)果, 并在方法調(diào)用和返回中發(fā)揮作用。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)、動態(tài)鏈接、方法出口等信息。每一個方法從調(diào)用直至執(zhí)行完成的過程,就對應(yīng)一個棧幀在虛擬機棧中從入棧到出站的過程。由于 Java 虛擬機堆棧從不直接操作, 除非是推送和彈出幀,因此Java 虛擬機堆棧的內(nèi)存不需要是連續(xù)的,可以對幀進行堆分配。

? ? ? ? 局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對象引用和returnAddress類型。局部變量表所需的內(nèi)存空間在編譯期間完成分配。當(dāng)進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。

Java虛擬機棧可能存在兩種異常情況

1)StackOverflowError 異常:

? ? 如果線程請求的棧深度大于虛擬機所允許的深度,將會拋出 StackOverflowError 異常;

2)OutOfMemoryError 異常:

? ? 如果虛擬機可以動態(tài)擴展,而在擴展的時候無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryError 異常。

3、本地方法棧(Native Method Stacks)

? ? ? 本地方法棧與虛擬機棧的區(qū)別是:虛擬機棧為虛擬機執(zhí)行Java方法(使用Java編寫的方法--字節(jié)碼)服務(wù);而本地方法棧則為虛擬機使用到的Native 方法(使用非Java語言編寫的方法)服務(wù)。

Java 虛擬機的實現(xiàn)可以使用傳統(tǒng)的堆棧 (俗稱 "C 堆棧") 來支持本機方法 (用 Java 編程語言以外的語言編寫的方法)。本機方法堆棧也可用于實現(xiàn) Java 虛擬機指令集的解釋器, 語言 (如 C)。Java 虛擬機實現(xiàn)不能加載本機方法并且本身不依賴于常規(guī)堆棧,不需要提供本機方法堆棧。如果提供, 則在創(chuàng)建每個線程時, 通常會為每個線程分配本機方法堆棧。如果該方法不是本機方法, 則 pc 寄存器包含當(dāng)前正在執(zhí)行的 Java 虛擬機指令的地址。如果線程當(dāng)前執(zhí)行的方法是本機的, 則 Java 虛擬機的 pc 寄存器的值是未定義的。Java 虛擬機的 pc 寄存器足夠?qū)? 可以在特定平臺上保存返回地址或本機指針。

? ? ? ? 本地方法棧與Java虛擬機棧類似也會產(chǎn)生StackOverflowError 和 OutOfMemoryError異常。

4、堆(Head)

? ? ? ? Java 虛擬機有一個在所有 Java 虛擬機線程之間共享的堆。堆是分配給所有類實例(對象)和數(shù)組的運行時數(shù)據(jù)區(qū)域。

? ? ? ? 堆是在虛擬機啟動時創(chuàng)建的。對象的堆存儲由自動存儲管理系統(tǒng) (稱為垃圾回收器) 回收;對象永遠不會顯式釋放。Java 虛擬機沒有特定類型的自動存儲管理系統(tǒng), 可以根據(jù)實現(xiàn)者的系統(tǒng)要求選擇存儲管理技術(shù)。堆可以是固定大小的, 也可以根據(jù)計算的要求進行擴展, 如果沒有必要使用較大的堆, 則可以收縮堆。堆的內(nèi)存不需要是連續(xù)的。堆是Java GC 垃圾收集器管理的主要區(qū)域。

? ? ? ? Java 虛擬機可以為程序員或用戶提供對堆初始大小的控制,如果堆可以動態(tài)展開或收縮, 則控制最大和最小堆大小。

? ? ? ? 以下特殊情況與堆相關(guān)聯(lián):

? ? ? ? 如果計算所需的堆數(shù)超過了自動存儲管理系統(tǒng)所能提供的堆, 則 Java 虛擬機將引發(fā) OutOfMemoryError

5、方法區(qū)(Method)

? ? ? ? 方法區(qū)和堆一樣,在所有 Java 虛擬機線程之間共享。方法區(qū)域類似于常規(guī)語言的編譯代碼的存儲區(qū)域, 也類似于操作系統(tǒng)進程中的 "文本" 段。它存儲著每個類結(jié)構(gòu), 譬如運行時常量池、字段和方法數(shù)據(jù), 以及方法和構(gòu)造函數(shù)的代碼, 包括類中使用的特殊方法和實例初始化以及接口初始化。方法區(qū)域是在虛擬機啟動時創(chuàng)建的。盡管方法區(qū)域在邏輯上是堆的一部分, 但可以選擇不進行垃圾收集或壓縮垃圾。

? ? ? 方法區(qū)域可以是固定大小的, 也可以根據(jù)計算的要求進行擴展, 如果沒有必要使用更大的方法區(qū)域, 則可以收縮。方法區(qū)域的內(nèi)存不需要是連續(xù)的。

? ? ? ? 如果計算所需的方法區(qū)域超過了自動存儲管理系統(tǒng)所能提供的方法區(qū)域, 則 Java 虛擬機將引發(fā) OutOfMemoryError

6、運行時常量池(Run-Time Constant Pool)

? ? ? 運行時常量池是方法區(qū)的一部分。運行時常量池是類文件中常量池表的每個類或每個接口的運行時表示形式。它包含多種類型的常量, 從編譯時已知的數(shù)字文本到必須在運行時解析的方法和字段引用。運行時常量池的功能類似于傳統(tǒng)編程語言的符號表, 盡管它包含的數(shù)據(jù)范圍比典型的符號表更廣泛。每個運行時常量池都從 Java 虛擬機的方法區(qū)域中分配而來。類或接口的運行時常量池是在 Java 虛擬機創(chuàng)建類或接口時構(gòu)造的。

? ? ? ? 創(chuàng)建類或接口時, 如果構(gòu)造運行時常量池所需的內(nèi)存超過了 Java 虛擬機的方法區(qū)域中可用的內(nèi)存, 則 Java 虛擬機將引發(fā) OutOfMemoryError。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容