java虛擬機內存結構

本篇文章主要是分享自己在《深入瞭解java虛擬機》一書中瞭解到知識,分享java虛擬節內存管理中各個區域的作用,服務對象以及其中可能產生的異常。
1.內存管理
1.1 程序計數器
程序計數器是一塊比較小的內存空間,他可以看做是當前線程所執行的字節碼的行號指示器,在虛擬機的概念模型裏,字節碼解析器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支,循環,跳轉,異常處理,線程恢復等基礎功能都需要依賴這個計數器來完成。
由於java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。因此爲了線程切換後能恢復到正確的執行位置,每條線程都需要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,我們稱這類內存區域爲“線程私有”的內存。
程序計數器是在java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。
1.2 java虛擬機棧
java虛擬機棧也是線程私有的,它的生命週期與線程相同,虛擬機棧描述的是java方法執行的內存模型:每一個方法在執行的同時都會創建一個棧幀(棧幀是方法運行時的基礎數據結構)用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。我們所說的棧就是java虛擬機棧,或者說是虛擬機棧中局部變量表部分。
局部變量表存放了9種基本類型,對象引用類型(這個引用類型不等同於對象本身可能是一個指向對象起始地址的引用指針,也可能是指向一個代表對象的句柄或者其他與此對象相關的位置)和returnAddress(指向了一個字節碼指令的地址)。
局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。
規定了兩種異常狀況:線程請求的棧深度大於虛擬機多允許的深度,將拋出StackOverflowError異常,如果可以動態擴展的虛擬機在擴展時無法申請到足夠的內存,就會拋出OutOfMemoryError異常。
1.3 本地方法棧
本地方法棧和虛擬機棧的區別是虛擬機展爲虛擬機執行java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的Native方法服務。
會拋出StackOverflowError異常和OutOfMemoryError異常。
1.4 java堆
java堆是java虛擬機所管理的內存中最大的一塊,Java堆是被所有線程共享的一塊內存區域,在虛擬機啓動時創建,此內存區域的唯一目的是存放對象實例。幾乎所有的對象實例都在這裏分配內存。
java堆也是垃圾收集器管理的主要區域,所以可以細分爲新生代和老生代,再分的話是Eden空間,From Survivor空間,To Survivor空間等。
如果在堆中沒有內存完成實例分配,堆也無法再擴展時,就會拋出OutOfMemoryError異常。
1.5 方法區
方法區也是各個線程共享的內存區域,用於存儲已被虛擬機加載的類信息,常量,靜態變量,就是編譯器編譯後的代碼等數據。
java虛擬機對方法區的現在很寬鬆,除了和java堆一樣不需要連續的內存和可以選擇固定大小或者可擴展外,還可以選擇不實現垃圾收集器。
當方法區無法滿足內存分配需求是,將拋出OutOfMemoryError異常。
1.6 運行時常量池
運行時常量池是方法區的一部分,用於存放編譯器生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。一個重要的特徵是具備動態性,也就是說可以在運行期間將新的常量放入池中。
拋出OutOfMemoryError異常。
2.直接內存直接內存不是虛擬機運行時數據區的一部分,也不是java虛擬機規範中定義的內存區域。但會被頻繁的調用。主要是針對存儲在java堆中的DirectByteBuffer對象(此對象屬於NIO類,基於通道和緩衝區,直接內存可以使用Native函數庫直接分配堆內存)作爲這塊內存的引用。
如果各個內存區域總和大於物理內存限制,包括物理的和操作系統的限制,從而導致動態擴展時出現的OutOfMemoryError異常。

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