1. 程式人生 > >第一章 深入理解jvm記憶體模型

第一章 深入理解jvm記憶體模型

java的記憶體模型

一.執行時資料區域
這裡寫圖片描述


java虛擬機器在程式執行時會建立不同的執行時資料區,有的區域會隨著虛擬機器啟動而存在,有的會隨著使用者執行緒存在而建立,jvm記憶體模型分為下面具體五部分:
這裡寫圖片描述

1.程式計數器

程式技術器是較小的一塊記憶體區域,可以看做是程式執行的位元組碼的行號指示器,位元組碼直譯器工作就是通過改變這個計數器來改變下一條執行的位元組碼指令,迴圈,異常處理,跳轉,執行緒回覆等功能。
由於jvm的多執行緒執行時由cpu控制迴圈切換執行緒並分配處理器執行時間進行執行,所以就需要這個程式計數器來操作,每個執行緒擁有自己私有的程式計數器用來記錄程式執行位置。
如果程式執行的是java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼的指令的地址,如果是native方法,則這個計數器的值為空。此區域是唯一一個基本不會出現oom的區域。

2.java虛擬機器棧
與程式計數器一樣,java棧也是執行緒私有,他描述的是java方法執行的記憶體模型,每個方法在執行的時候會建立棧幀。這個棧幀會包含區域性變量表,運算元棧,動態連結,方法出口。方法的呼叫與結束,對應的是java棧幀的入棧和出棧。大多數人把java記憶體區域劃分為java棧和java堆記憶體區域,這個劃分比較粗糙,說明大多數只關注這個兩個區域的問題,這個所指的棧就是java虛擬機器棧,進一步其實關注的是區域性變量表的內容。

區域性變量表存放了編譯期間可知的基本資料型別(boolean,byte,int,long…….),物件引用(可能是物件的起始的引用指標,也可能是物件的控制代碼)和returnAdress型別。
如果執行緒請求java棧的深度大於虛擬機器所允許的深度,則會丟擲stackoverflow異常,如果在申請記憶體區域時,無法獲得足夠記憶體,則會丟擲oom。

3.本地方法棧
本地方法棧與java虛擬機器棧非常相似,他們的區別只是,java虛擬機器棧是為虛擬機器執行java方法服務,而本地方法棧是為java的native方法服務,如:hashcode()等方法。與java虛擬機器棧一樣,本地方法棧也會丟擲oom異常和Stack Overflow

4堆記憶體
Java Heap為Java堆記憶體,是java虛擬機器管理記憶體中最大的一塊,它是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。java堆記憶體存放物件例項,幾乎所有的物件例項都在這裡分配空間,也是垃圾回收的主要區域。
垃圾回收採用分代回收的方法,因此堆記憶體被分為 新生代,老年代:再細分一點就是:Eden空間,from Survivor空間, To Survivor空間等。從記憶體分配的角度看,執行緒共享的java堆中可能劃分出多個執行緒私有的分配緩衝區。

5.方法區

方法區和堆記憶體一樣,是執行緒共享的記憶體區域,用於存放已載入的類資訊,常量,靜態變數,以及即時編譯器編譯後的程式碼等資料。

6.執行時常量池

執行時常量池是方法區的一部分,class資訊除了版本,欄位,方法,介面等資訊外,還有常量池,用於存放編譯期間生成的各種字面量和符號引用。執行時常量池也會受到方法區的限制,當不能分配記憶體時會丟擲oom

7.直接記憶體

直接記憶體並不是java虛擬機器執行時資料區的一部分,也不是java虛擬機器規範中的記憶體區域,但是這個區域也被頻繁使用,也會造成oom。
在jdk引入了nio的概念,引入了一種基於通道和緩衝區的io方式,他可是直接使用native庫中的方法直接分配堆外記憶體,然後通過儲存在java堆中的DirecteByteBuffer物件進行對這塊記憶體進行操作。這樣能在一些場景中顯著提高效能。因為避免了在java堆中和native堆中來回複製資料。這個地方受到本機記憶體的大小的限制,當使用nio時,並且本機記憶體不足時會造成oom。