深入理解Java虛擬機-內存區域

java虛擬機執行Java程序把管理的內存分爲若干個不同的數據區域。各區域有各的用途,創建銷燬時間,有些區域隨着虛擬機進程啓動而存在,有些區域是依賴用戶線程的啓動和結束而建立和銷燬。java虛擬機管理的內存區域包括以下幾個運行時數據區,如下圖

1、程序計數器(program counter register)
較小的內存空間,當前線程所執行的字節碼的行號指示器。字節碼解釋器工作時就是通過改爲這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
java虛擬機的多線程是線程輪流切換CPU時間片來實現,任何時刻,一個處理器只能執行一個線程的指令。線程切換後恢復到執行位置,每個線程需要一個獨立計數器,線程私有。
java方法,計數器是虛擬機字節碼地址;native方法,計數器爲空,計算器必須要容納方法的返回地址或者指針。該區域唯一一個沒有規定OutOfMemoryError的區域。
2、虛擬機棧
線程私有,聲明週期與線程相同。虛擬機棧描述的是java方法執行的內存模型,每個方法執行創建一個棧幀存儲操作數棧、動態鏈接、局部變量表等信息。每個方法調用到完成相當於虛擬機棧中的入棧與出棧。
固定大小,也可擴展與收縮。固定大小需要獨立創建。動態擴展與收縮提供最大與最小。
規定兩種異常:棧深度超過虛擬機的深度報StackOverflowError;擴展內存時,棧無法申請到內存,報OutOfMemoryError錯誤
3、本地方法棧
與虛擬機棧相似,也拋兩個異常。對本地方法的使用語言使用方式與數據結構沒有規定。
4、java堆
內存最大,線程共享,幾乎存放所有對象實例以及內存分配。所有類的實例和數組對象都要在堆中分配。
java堆是垃圾收集器的主要區域,也稱GC堆。收集器按分代收集算法,細分爲新生代和老年代,新生代又分Eden空間、From Survivor、To Survivor空間。線程共享的java堆中可能劃分多個線程私有的分配緩衝區。反正存放實例,再分爲了更快回收與分配。
java堆可以使物理不連續,邏輯上連續,可固定大小,可擴展與收縮 (-Xms與-Xms控制),內存不足報OutOfMemory異常。
5、方法區
線程共享區域,存儲加載的類信息、常量、靜態變量、即時編譯器編譯後的代買數據。虛擬機啓動時方法被創建。
HotSpot虛擬機方法區被稱爲永久代,永久代不等價方法區,把GC分代收集擴展到方法區,jdk8移除永久代,用本地內存代替。
不要連續內存,可以擴展內存,可以選擇不垃圾收集(垃圾收集不理想),內存不足時報OutOfMemory異常。
6、運行時常量時
方法區的一部分。class方法中除了有類的版本、字段、方法、接口等描述信息外,還有常量表,存儲編譯期生成的各種字面量和符號引用。
java常量不一定只在編譯器產生,程序也可以新添加,如String類的intern()方法。
常量池內存不足報OutOfMemory異常。
7、直接內存
不是運行時數據區的一部分,也不是java虛擬機規範定義的內存區域,但這部分內存頻繁使用,也可能導致OutOfMemoryError錯誤出現。垃圾收集時,會對直接內存收集,但不會像新生代和老年代那樣,發現不足就觸發收集,它只能等到老年代滿了後FullGC時,順便清理掉直接內存中廢棄的對象。
jdk1.4加入NIO,引入基於通道(channel)與緩衝區(Buffer)的I/O方法,它可以直接使用Native函數直接分配堆外內存,通過java堆中DirectByteBuffer對象作爲這塊內存的引用進行操作。提高一些場景性能,避免java堆與native堆中來回複製數據。

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