《深入理解JVM》內存模型

       這是入職的第一篇博客,關於JVM的,恰好畢業時淘來了一本《深入理解JVM》,慶幸!

       JVM運行時的數據區域劃分圖如下,該圖是JVM內存模型最主要的內容。

                        

       從圖中可以看出來,JVM將內存主要劃分爲五個部分:程序計數器、Java虛擬機棧、本地方法棧、Java堆和方法區。這些被劃分爲用途不一的數據區域有着各自的特點,它們都有自己創建和銷燬的時間,有的區域隨着進程的啓動而存在,有的是伴隨着用戶線程的啓動而建立、隨着線程的結束而銷燬。


(一) 程序計數器(Program Counter Register)

        1> 內存空間較小;

        2> 當前線程所執行的字節碼行號指示器;

功能:a、在JVM中,字節碼解釋器的工作進行就是通過改變計數器的值來選取下一條需要執行的字節碼指令

           b、在3>中有解釋,是作爲線程切換回來繼續執行的標記點

        3> 線程私有;

線程私有:通俗來講就是每一個線程在執行時都有一個獨立的程序計數器,各個線程被獨立存儲。目的是爲了記錄所執行的線程進行到了哪一步。這樣設計的原因主要是由多線程的實現方式所決定的,在Java虛擬機中,多線程的實現是通過線程輪流切換並分配處理器執行時間的方式,也就是在任何一個具體的時刻下,一個處理器只能夠執行一個線程下的代碼指令,這樣在不斷的線程切換過程中,同一個線程想要繼續往下執行,就必須知道它上一次執行的位置,這個工作就是通過程序計數器完成的。

         4> 計數器的值;

若線程正在執行的是Java方法:正在執行的虛擬機字節碼指令的地址;

若線程正在執行的是Native方法:空值(Undefined);

Native方法(本地方法):爲了補充Java語言無法直接訪問系統底層的一種方法,由C或C++語言完成,實際上Native Method就是Java調用非Java代碼的接口。

         5> 計數器這塊內存區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。

         6> 生命週期與線程相同。


(二)Java虛擬機棧(Java Stack)

         1> 定義:描述Java方法執行的內存模型;

a、詳細解釋:每個方法執行時都會創建一個棧幀,在這個棧幀中存放着“局部變量表、操作數棧、動態鏈接、方法出口等”。

         以我的理解就是這一塊內存就是一個棧,棧幀是Java虛擬機棧的諸多元素,每一個棧幀都代表這一個方法正在被執行,其中存放着一些有關該方法中信息。

         每一個方法從調用一直到執行結束,也就對應着一個棧幀在Java虛擬機棧中入棧出棧的過程。

b、局部變量表:

         基本數據類型、(64位的long和double類型的數據會佔用2個局部變量空間,其餘佔1個)

         對象引用、(reference類型??,不同於對象本身,可能是一個指向對象起始地址的引用指針,也可能                                              是指向一個代表對象的句柄或其他與此對象相關的位置)

         returnAddress類型 、(指向了一條字節碼指令的地址)

局部變量表所需的內存空間在編譯期間完成分配,所以在線程進行時調用了一個方法,爲之創建的棧幀中局部變量空間是完全確定的,並且在方法執行過程中不會改變局部變量表的大小。              

          2> 線程私有;

線程私有: 也就是和計數器一樣,每一個線程有獨立的Java虛擬機棧,這個線程中的每個方法執行過程就會創建一個棧幀,方法執行的全過程就是棧幀在該線程對應的虛擬機棧中入棧和出棧的過程。

          3> 生命週期與線程相同;

          4> 該內存區域兩種異常狀況:

              a、線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常;

              b、若虛擬機支持動態擴展,如果擴展時無法申請到做夠的內存,就會拋出OutOfMemoryError異常。

           StackOverFlowError表示當前線程申請的棧超過了事先定好的棧的最大深度,但內存空間可能還有很多。

           而OutOfMemoryError是指當線程申請棧時發現棧已經滿了,而且內存也全都用光了。

          5> 不能簡單地將Java內存區簡單分爲堆和棧。

這樣區分太過粗糙,只不過是將對象和局部變量區分開,簡單地認爲對象存放在堆中,局部變量存放在棧中。其實從上面的整理中也可以看出來,Java虛擬機棧實際上是由這些棧幀組成的,而每個棧幀中的內容並不只有局部變量表。


(三)本地方法棧

            1> 定義:與Java虛擬機棧的定義很相似,可以說是Native方法執行的內存模型;

            2> 虛擬機規範中對本地方法棧中方法使用的語言、使用方式與數據結構並沒有強制規定。甚至有的虛擬機(Sun HotSpot)直接就把本地方法棧和虛擬機棧合二爲一;

            3> 拋出StackOverflowError和OutOfMemoryError異常的情況與Java虛擬機棧是一樣的;

            4> 其他特性參考Java虛擬機棧。


(四)Java堆

            1> 系Java虛擬機所管理內存中最大的一塊,虛擬機啓動時創建;

            2> 被所有線程共享;

所有地線程都可以訪問不同地對象,從內存分配地角度來看,線程共享地Java堆中可能劃分出多個線程私有地分配緩衝區(TLAB),不過無論如何劃分,無論哪個區域,存放地都是對象實例,這樣不同地線程將各自地對象實例放在了看似共享的Java堆的各自的緩衝區上,這樣的好處是可以更好的回收內存,也可以更快分配內存。

            3> 唯一目的就是存放對象實例,幾乎所有實例對象都存在此處;

在Java虛擬機規範中描述爲:所有的對象實例以及數組都要在這裏分配內存。但是隨着JIT編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所以這裏會嚴謹地加上“幾乎所有”而不是全部,至於什麼是逃逸分析,棧上分配,標量替換,以後學習中應該會專門去了解學習一下吧。

            4>可以處於物理上不連續的內存空間,但邏輯上需要連續; 

            5> 可以實現固定大小的,也可以是可擴展的。若在堆中沒有內存完成實例分配,並且堆也無法再擴展時,將拋出OutOfMemoryError異常;

            6> 又稱“GC堆'(Garbage Cpllected Heap)

內存回收用到的終極算法:分代收集算法,今後可以專門學習一下,該算法也是多個算法的整合。


(五) 方法區(Method Area)

            1> 與Java堆類似,各線程共享的內存區域;

            2> 存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等;

            3> 規範中描述爲堆的一個邏輯部分,習慣稱爲Non-Heap(非堆),目的是爲了與Java堆區分;

            4> 被稱作“永久代”;

本質上兩者並不一樣,這樣的叫法是因爲HotSpot虛擬機的設計團隊選擇把GC分代收集擴展至方法區,或者說使用永久代來實現方法區而已,這樣GC收集器就能像管理Java堆一樣管理這部分內存,省去專門爲方法區編寫內存管理代碼的工作。當然方法區也可以不進行GC收集。

            5> 不需要連續的內存和可以選擇固定大小或者可擴展外,也可以不實現GC收集;

該區域的內存回收目標主要是針對常量池的回收和對類型的卸載,但效果不好,條件苛刻,但是對於這部分的回收確實是有必要的。

            6> 當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常


(六) 運行時常量池

            1> 方法區的一部分;

Class文件除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯時生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。

            2> 受到方法區內存的限制,當常量池無法再申請到內存時會拋出OutOfMemoryError異常;


(七) 直接內存

            1> 不屬於虛擬機運行時數據區的一部分,也不是規範中的定義;

            2> JDK1.4加入了NIO類,一種基於通道與緩衝區的新I/O方式,NIO可以使用Native函數庫直接分配堆外內存,然後通過一個存儲在Java堆中的DirectByteBuffer對象作爲直接內存的引用來操作直接內存,這樣可以避免在Java堆和Native堆來回複製數據,從而提高性能;

           3> 受總內存影響,也會出現OutOfMemoryError異常。


         以上總結的就是JVM內存模型的相關概念和知識點,前五項以及那張內存模型圖需要牢記,其中有些許疑問,不過也都是某些概念上的問題,具體關於每一塊內存區域的定義作用,拋出的異常類型,已經理解。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章