1. 程式人生 > 其它 >深解JVM 2-記憶體結構

深解JVM 2-記憶體結構

深解JVM 1-Java虛擬機器基本原理 - chch213 - 部落格園 (cnblogs.com)

上一篇介紹了一下JVM的一些基本原理概念。

本篇主要針對執行時資料區進行解析。

執行時資料區儲存了哪些資料?

a) 程式計數器(PC暫存器)

由於在JVM中,多執行緒是通過執行緒輪流切換來獲得CPU執行時間的,因此,在任一具體時刻,一個CPU的核心只會執行一條執行緒中的指令,

因此,為了能夠使得每個執行緒都線上程切換後能夠恢復到切換之前的程式執行位置,每個執行緒都需要有自己獨立的程式計數器,並且不能互相被幹擾,

否則就會影響到程式的正常執行次序。因此,可以這麼說,程式計數器是每個執行緒所私有的

。由於程式計數器中儲存的資料所佔空間的大小不會隨程式的執行而發生改變,

因此,對於程式計數器是不會發生記憶體溢位現象(OutOfMemory)的。

b) java棧

Java棧中存放的是一個個的棧幀,每個棧幀對應一個被呼叫的方法,在棧幀中包括區域性變量表(Local Variables)、運算元棧(Operand Stack)、指向當前方法所屬的類的執行時常量池(執行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、

**方法返回地址(Return Address)**和一些額外的附加資訊。當執行緒執行一個方法時,就會隨之建立一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。

c)本地方法棧

本地方法棧與Java棧的作用和原理非常相似。區別只不過是Java棧是為執行Java方法服務的,而本地方法棧則是為執行本地方法(Native Method)服務

d)堆

Java中的堆是用來儲存物件本身的以及陣列(陣列引用是存放在Java棧中的)。堆是被所有執行緒共享的,在JVM中只有一個堆。

e)方法區

與堆一樣,是被執行緒共享的區域。在方法區中,儲存了每個類的資訊(包括類的名稱、方法資訊、欄位資訊)、靜態變數常量以及編譯器編譯後的程式碼等。

在Class檔案中除了類的欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用來儲存編譯期間生成的字面量和符號引用。

在方法區中有一個非常重要的部分就是執行時常量池

,它是每一個類或介面的常量池的執行時表示形式,在類和介面被載入到JVM後,

對應的執行時常量池就被創建出來。當然並非Class檔案常量池中的內容才能進入執行時常量池,在執行期間也可將新的常量放入執行時常量池中,比如String的intern方法。

JVM記憶體溢位的情況

a) 程式計數器(Program Counter Register)

每條執行緒都有一個獨立的的程式計數器,各執行緒間的計數器互不影響,因此該區域是執行緒私有的。該記憶體區域是唯一一個在Java虛擬機器規範中沒有規定任何OOM(記憶體溢位:OutOfMemoryError)情況的區域。

b)Java虛擬機器棧(Java Virtual Machine Stacks)

在Java虛擬機器規範中,對這個區域規定了兩種異常情況:

1、如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常。

2、如果虛擬機器在動態擴充套件棧時無法申請到足夠的記憶體空間,則丟擲OutOfMemoryError異常。

這兩種情況存在著一些互相重疊的地方:當棧空間無法繼續分配時,到底是記憶體太小,還是已使用的棧空間太大,其本質上只是對同一件事情的兩種描述而已。

在單執行緒的操作中,無論是由於棧幀太大,還是虛擬機器棧空間太小,當棧空間無法分配時,虛擬機器丟擲的都是StackOverflowError異常,而不會得到OutOfMemoryError異常。

而在多執行緒環境下,則會丟擲OutOfMemoryError異常。

(37條訊息) Java虛擬機器OOM之虛擬機器棧和本地方法棧溢位_高山流水遇知音_的部落格-CSDN部落格_虛擬機器棧會oom嗎

c)堆Java Heap

Java Heap是Java虛擬機器所管理的記憶體中最大的一塊,它是所有執行緒共享的一塊記憶體區域。幾乎所有的物件例項和陣列都在這類分配記憶體。Java Heap是垃圾收集器管理的主要區域,因此很多時候也被稱為“GC堆”。

  根據Java虛擬機器規範的規定,Java堆可以處在物理上不連續的記憶體空間中,只要邏輯上是連續的即可。如果在堆中沒有記憶體可分配時,並且堆也無法擴充套件時,將會丟擲OutOfMemoryError異常。

d)方法區域,又被稱為“永久代”,當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常。