1. 程式人生 > >JVM記憶體模型

JVM記憶體模型

注意:java8中記憶體模型發生了變化,Metaspace替換了PermGen。

jvm記憶體結構大概分為:

序號 名稱 是否共享 作用
1 堆(head) 執行緒共享 所有的物件例項以及陣列都要在堆上分配,回收器主要管理的物件
2 方法區(MEATHOD AREA) 執行緒共享 儲存類資訊、常量、靜態變數、即使編譯器編譯後的程式碼
3 PC暫存器(PC Register) 執行緒私有 指向下一條要執行的指令
4 方法棧(JVM Stack) 執行緒私有 儲存區域性變量表、操作棧、動態連結、方法出口、物件指標
5

本地方法棧(native method stack)

執行緒私有 為虛擬機器使用到的Native方法服務,如java使用c或者c++編寫的介面服務時,程式碼在此區執行

記憶體圖:

1、堆:

堆的作用存放物件例項和陣列。從結構上講可分為新生代和老年代。新生代又可以分為Eden空間、Form Survivor空間(s0)、To Survivor空間(s1)。所有新生成的物件首先都是放在年輕代的。需要注意,Survivor兩個區是對稱的,沒先後關係,所以同一個區中可能同時存在從Eden複製過來的物件和從前一個Survivor複製過來的物件,而複製到年老區的只有從第一個Survivor取過來的物件,而且,Survivor區總有一個是空的。

控制引數

-Xms:設定堆的最小空間大小;

-Xmx:設定堆的最大空間大小;

-XX:NewSize設定新生代最小空間大小;

-XX:MaxNewSize設定新生代最大空間大小;

垃圾回收

此區域是垃圾回收的主要操作區域。

異常情況

 如果在堆中沒有記憶體完成例項分配,並且堆也無法擴充套件時,將會丟擲OutOfMemoryError異常。

2、方法區

 方法區(method area)與java堆一樣,是執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。雖然java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的應該是與java堆區分開來。

很多人願意把方法區稱為“永久代”(Permanent Generation),本質上二者並不等價,僅僅是因為HotSpot虛擬機器的設計團隊選擇把GC分代收集擴充套件至方法區,或者說使用永久代來實現方法區而已。對於其他虛擬機器(如BEA JRockit、IBM J9等)來說是不存在永久代概念的,在java8中永生代徹底消失了。

控制引數

-XX:PermSize 設定最小空間;

-XX:MaxPermSize 設定最大空間;

垃圾回收

對此區域會涉及但是很少進行垃圾回收。這個區域的記憶體回收目標主要是針對常量池的回收和對型別的解除安裝,一般來說這個區域的回收“成績”比較難以令人滿意。

異常狀況

根據java虛擬機器規範的規定,當方法區無法滿足記憶體分配需求時,將丟擲OOM異常。

3、PC計數器

它的作用可以看做是當前執行緒所執行的位元組碼的行號指示器

異常狀況

此記憶體區域是唯一一個在java虛擬機器規範中沒有規定任何OOM情況的區域。

4、方法棧

每次執行緒會有一個私有的棧。每個執行緒中方法的呼叫又會在本棧中建立一個棧幀。在方法棧中會存放編譯期可知的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(reference 型別,它不等同已物件本身。區域性變量表所需的記憶體空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的區域性變數空間是完全確定的,在方法執行期間不會改變區域性變量表的大小)

控制引數:

-Xss控制每個執行緒棧的大小

異常情況:

在java虛擬機器規範中。對這個區域規定了兩種異常狀況:

(1)、將丟擲StackOverflowError:異常執行緒請求的棧深度大於虛擬機器所允許的深度時丟擲;

(2)、OOM異常:虛擬機器棧可以動態擴充套件,當擴充套件時無法申請到足夠的記憶體時會丟擲。

5、本地方法棧

本地方法棧(Native Method Stacks)與虛擬機器棧所發揮的作用是非常相似的,其區別不過是虛擬機器棧為虛擬機器執行java方法(也就是位元組碼)服務,而本地方法棧則是為虛擬機器使用到的Native方法服務。

控制引數

在 Sun JDK中本地方法棧和方法棧是同一個,因此也可以使用-Xss控制每個執行緒的大小。

異常情況

與虛擬機器一樣,本地方法棧區域也會丟擲StackOverflowError和OOM異常。