1. 程式人生 > >【JVM】上帝視角看JVM記憶體模型,分而治之論各模組詳情

【JVM】上帝視角看JVM記憶體模型,分而治之論各模組詳情

1. 上帝視角

【樹看JVM】

【圖看JVM】


2. 分而治之

 2.1 堆區

    構成:堆區由新生代和老年代組成,新生代中包含伊甸區(Eden)、倖存者區(survivor from 、survivor to)和老年代。

    GC:當建立新的物件時,物件首先會被放入Eden和survivor from中,每經歷一次GC存活下來的物件,年齡都會加1。在進行了第一次GC後,在Eden中仍然存活的物件,將被放入survivor to ;而survivor from中的存活的物件將由年齡閥值(maxTenuringThreshold)來決定,如果年齡不超過maxTenuringThreshold的話,將被放入survivor to,如果超過的話,就被放入老年代。

    在經歷GC之後,Eden和survivor from 都被清空,此時,原先的survivor from轉變為survivor to的角色,原先的survivor to轉變成survivor from的角色,下一次的GC將會依據上一個原理,繼續進行。當survivor to滿了之後,survivor to 中的物件將會被放入老年代。

    除了年齡閥值會觸發物件晉升到老年代之外,還有以下第二種情況能夠觸發:

    前提:survivor to中,相同年齡的物件所佔的空間超過一半。

    觸發:物件的年齡超過了上述前提中物件的年齡,就會直接被放入老年代。

    因此,倖存者區存放的資料是Eden區GC後拷貝過來的資料,老年代存放的是資料是倖存者區GC後拷貝過來的資料

 2.2 棧區

        棧區中儲存的是一個一個的幀(stack frame),每一個棧幀對應一個被呼叫的方法,它與方法的生命週期一致,隨著方法的呼叫而被建立,隨著方法的結束而銷燬。棧幀中存放的是區域性變量表(基本資料型別、引用),運算元棧、指向當前方法所屬的類的執行時常量池的引用等資訊。(執行時常量池在方法區中)。

        

 2.3 方法區

    方法區由程式碼快取、執行時常量池、持久代(JDK1.8後被刪除)組成。

    · 持久代:在JDK1.6時方法區存放的是類的結構定義、方法、建構函式、以及存放靜態變數,在JDK1.7之後,方法區的持久代被刪除,取而代之的是元空間(metaSpace),元空間在本地記憶體中,與持久代類似,是對JVM規範中方法區的實現。

    · 程式碼快取:程式碼快取中存放的是JIT(just in time)編譯器編譯後的與硬體相關的程式碼。可以通過ReservedCodeCacheSize 和 InitialCodeCacheSize兩個引數設定。

    · 執行時常量池:被所有執行緒共享,儲存的是虛擬機器載入Class之後的常量池資料(常量池是Class的一部分,儲存著類、介面、方法中的常量)

 2.4 元空間(metaSpace)

    元空間在JDK1.7時開始取代方法區中的持久代(PermGen),那麼,為什麼要刪除持久代,讓元空間取而代之?官方解釋如下圖:


    從官方的解釋可以看出,由於JRokit中沒有持久代而不需要配置,而刪除持久代是官方為了融合JRockit與HotSpot所努力的一部分,所以在JDK1.7開始逐步開始取代持久代,到JDK1.8之後徹底刪除。

    並且,類和方法的資訊大小難以確定,永久帶經常會發生記憶體溢位(OOM),java.lang.OutOfMemoryError: PermGen

(關於元空間的溢位,計劃在下一篇博文與其它記憶體溢位的異常一起整理,這裡就不再贅述元空間的OOM)

 2.5 本地方法棧

    與前面談到的虛擬機器棧類似,區別在於虛擬機器棧為虛擬機器呼叫的Java方法服務,本地方法棧是為虛擬機器呼叫的本地方法(Native Method)服務。

Mative Method是一個Java呼叫一個非Java程式的介面,該方法的實現由非Java語言來實現

-------------------------

以下描述擷取自《深入理解Java虛擬機器:JVM高階特性與最佳實踐》 作者: 周志明 

本地方法棧(Native Method Stacks)與虛擬機器棧所發揮的作用是非常相似的,其區別不過是虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務,而本地方法棧則是為虛擬機器使用到的Native方法服務。虛擬機器規範中對本地方法棧中的方法使用的語言、使用方式與資料結構並沒有強制規定,因此具體的虛擬機器可以自由實現它。甚至有的虛擬機器(譬如Sun HotSpot虛擬機器)直接就把本地方法棧和虛擬機器棧合二為一。與虛擬機器棧一樣,本地方法棧區域也會丟擲StackOverflowError和OutOfMemoryError異常。

-----------------------------------------

 2.6 程式計數器(PC)

    程式計數器記錄的是執行緒下一步要執行的指令位元組碼地址。在多執行緒中,各執行緒之間是搶CPU的關係,要根據搶得時間片的CPU時間資源進行執行緒切換,因此,每個執行緒都有一個獨立的程式計數器,記錄各個執行緒下一步要執行的指令,這樣才能夠正常切換。

參考及推薦: