1. 程式人生 > 程式設計 >JVM記憶體結構與記憶體模型

JVM記憶體結構與記憶體模型

一、 Jvm記憶體結構

模組分解

1. 程式計數器(執行緒私有)

(1) 是什麼?

    程式計數器是當前執行緒所執行的位元組碼的行號指示器。

(2) 作用?

    位元組碼直譯器通過改變這個計算器的值來選擇下一條需要執行的位元組碼指令,分支,迴圈,跳轉,異常處理,執行緒恢復,如果執行的是Native方法,這個計算器的值則為空

2. Java虛擬機器器棧(執行緒私有)

(1) 是什麼

    Java虛擬機器器棧描述的是Java方法執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀,每個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器器棧中入棧到出棧的過程。

(2) 組成

① 區域性變量表

    存放了編譯期可知的基本型別、物件引用型別和returnAddress型別(指向一條位元組碼指令的地址。即程式就是儲存在方法區的位元組碼指令,而 returnAddress 型別的值就是指向特定指令記憶體地址的指標)

② 運算元棧

    運算元是一個後入先出棧,JVM所有的操作碼都是對運算元棧上的資料進行操作,對於每一個方法的呼叫,JVM會建立一個運算元棧,以供計算使用。

    例如 a = b + c 的位元組碼執行過程中運算元棧以及區域性變量表的變化如下圖所示。

    區域性變量表中儲存著a、b、c 三個區域性變數,首先將b和c分別入棧

③ 動態連結

    執行期間轉化為直接引用,就稱為動態連結。Class位元組碼的常量持中存有大量的符號引用,在執行期才將符號引用變成直接引用(也就是指向資料),可以是方法或者欄位的引用。

④ 方法出口

    即本方法執行後下一步指令的地址,方法正常退出時,呼叫者PC計數器的值就可以作為返回地址,異常退出時,返回地址是要通過異常處理器來確定。

3. 本地方法棧(執行緒私有)

(1) 是什麼?

    儲存native方法進入區域的地址

4. Java堆(執行緒共享)

(1) 是什麼?

    所有的物件例項以及陣列都要在堆上分配。是垃圾收集器管理的主要區域。

(2) 分割槽

① 新生代: Eden區、Survivor From區、Survivor To區
② 老年代

5. 方法區(執行緒共享)

(1) 是什麼

    方法區用於儲存已被虛擬機器器載入的類資訊、方法、常量、靜態成員變數、JIT(即時編譯器)編譯後的程式碼等資料,在類載入時分配。

(2) 也叫非堆,分配在元空間

    元空間:類的元資料,如方法資料、方法資訊(位元組碼,棧和變數大小)、執行時常量池、已確定的符號引用和虛方法表等方法區的資料,儲存在本地記憶體區域(堆外記憶體)

6. 執行時常量池(執行緒共享)

(1) 是什麼

    執行時常量池用於存放編譯期和執行期生成的各種字面量和符號引用。這部分內容將在類載入後進入方法區的執行時常量池中存放。屬於方法區的一部分

(2) 字面量和符號引用

    字面量:1.字串;2.基本型別值;3.final常量     符號引用:1.類和方法的全限定名;2.欄位的名稱和描述符;3.方法的名稱

二、 Jvm記憶體模型

1. 定義

    由於不同平臺記憶體模型的差異,有可能導致程式在不同平臺的併發訪問出錯。Java記憶體模型(Java Memory Model,JMM)是遮蔽各種硬體和作業系統的記憶體訪問差異,以實現讓Java程式在各種平臺下都能達到一致的記憶體訪問效果。

2. 具體操作

    定義程式中各個變數的訪問規則,即在虛擬機器器中將變數儲存到記憶體和從記憶體中取出變數的底層細節。
    此處的變數是指例項欄位,靜態欄位和構成陣列物件的元素,不包括區域性變數與方法引數

3. 主記憶體和工作記憶體

    Jvm記憶體模型規定所有的變數都儲存在主記憶體中,每條執行緒還有自己的工作記憶體,工作記憶體儲存了被該執行緒使用到的變數的主記憶體副本拷貝。

4. synchronization、final、volatile

(1) synchronization

① 互斥

    對於一個monitor物件,當被一個執行緒持有,其他執行緒只能等待

② 可見性

    保證了執行緒在同步程式碼塊期間寫入動作,對於後續進入該程式碼塊的執行緒是可見的(持有相同monitor物件的執行緒)。
    當前執行緒釋放monitor物件,作用是把cpu快取資料重新整理到主記憶體中;其他執行緒進入該程式碼塊時,需要獲取monitor物件,會使cpu快取失效,從而使變數從主記憶體中重新載入。

③ 禁止指令重排序

(2) final

① 禁止指令重排序
② 可見性

    被final修飾的欄位在構造器中一旦初始化完成,並且構造器沒有把”this”引用傳遞出去(“this”引用逃逸是一件很危險的事情,其他執行緒有可能通過這個引用訪問到”初始化了一半”的物件),那麼其他執行緒就能看見final欄位的值。

(3) volatile

① 可見性
② 禁止指令重排序

5. 示例

(1) 重排序

(2) 可見性

(3) 互斥性

作者:陶章好
連結:juejin.im/post/5d6281… 來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。