1. 程式人生 > >java內存結構(執行時數據區域)

java內存結構(執行時數據區域)

什麽 article mod 字節碼 獨立 強制 工作 垃圾收集 緩沖

java虛擬機規範規定的java虛擬機內存事實上就是java虛擬機執行時數據區,其架構例如以下:
技術分享

當中方法區和堆是由全部線程共享的數據區。

Java虛擬機棧。本地方法棧和程序計數器是線程隔離的數據區。

(1).程序計數器:

是一塊較小的內存空間,其作用能夠看作是當前線程所運行的字節碼的行號指示器,字節碼解析器工作時通過改變程序計數器的值來選取下一條須要運行的字節碼指令。

程序的分支、循環、跳轉、異常處理以及線程恢復等基礎功能都是依賴程序計數器來完畢。

Java虛擬機的多線程是通過線程輪流切換並分配處理器運行時間片來實現。在不論什麽一個時刻,一個處理器僅僅會運行一條線程指令。因此。為了確保線程切換之後能恢復到正確的運行位置,每條線程都須要一個獨立的程序計數器,因此程序計數器是線程私有的內存。

程序計數器是java虛擬機中唯一一個沒有規定不論什麽內存溢出OutOfMemoryError的內存區域。

(2).java虛擬機棧:

Java虛擬機棧也是線程私有的。它的生命周期與線程同樣。

虛擬機棧描寫敘述的是java方法運行的內存模型:每一個方法被運行時都會同一時候創建一個棧幀用於存放局部變量表、操作數棧、動態連接和方法出口等信息。每一個方法被調用直至運行完畢過程,就相應著一個棧幀在虛擬機中從入棧到出棧的過程。

Java虛擬機棧的局部變量表存放了編譯器可知的8種java基本類型數據、對象引用(註意不是對象實例本身)、方法返回地址returnAddress。

Java虛擬機棧的局部變量表空間單位是槽(Slot),當中64位長度的double和long類型會占用兩個slot。其余的數據類型僅僅占用一個slot。

局部變量表所需內存空間在編譯期間完畢分配,當進入一個方法時。該方法須要在幀中分配多大的局部變量空間是全然確定的,在方法執行期間不會改變局部變量表的大小。

Java虛擬機棧有兩種異常狀況:假設線程請求的棧深度大於虛擬機所同意的最大深度時,拋出StackOverflowError異常;假設虛擬機棧能夠動態擴展,當擴展時無法申請到足夠內存時會拋出OutOfMemoryError異常。

(3).本地方法棧:

本地方法棧與java虛擬機棧作用很類似。其差別是:java虛擬機棧是為虛擬機運行java方法服務。而本地方法棧是為虛擬機調用的操作系統本地方法服務。

Java虛擬機規範沒有對本地方法棧的實現和數據結構做強制規定。Sun HotSpot虛擬機直接把java虛擬機棧和本地方法棧合二為一。

與java虛擬機棧類似,本地方法棧也會拋出StackOverflowError異常和OutOfMemoryError異常。

(4).堆:

堆是java虛擬機所管理的內存區域中最大一塊,java堆是被全部線程所共享的一塊內存區域。在java虛擬機啟動時創建。堆內存的唯一目的就是存放對象實例。差點兒全部的對象實例都是在堆分配內存。

Java堆是垃圾收集器管理的主要區域。從垃圾回收的角度看,因為如今的垃圾收集器基本都採用的是分代收集算法。因此java堆還能夠初步細分為新生代和年老代。

Java虛擬機規範規定,堆能夠處於物理上不連續的內存空間中,僅僅要邏輯上是連續的就可以。在實現上即能夠是固定大小的。也能夠是可動態擴展的。假設在堆中沒有內存完畢實例分配,而且堆大小也無法在擴展時,將會拋出OutOfMemoryError異常。

(5).方法區:

方法區與堆一樣,是被各個線程共享的內存區域。它用於存儲已被虛擬機載入的類信息、常量、靜態變量、即時編譯後的代碼等數據。盡管java虛擬機規範把方法區描寫敘述為堆的一個邏輯部分,可是方法區卻有一個別名叫Non-Heap(非堆)。

Sun HotSpot虛擬機把方法區叫永久代(Permanent Generation),方法區中最重要的部分是執行時常量池。

Class文件裏除了有類的版本號、字段、方法、接口等描寫敘述信息外,另一項信息是常量池。用於存放編譯期生成的各種字面變量、符號引用、直接引用等,這些內容將在類載入後存放到方法區的執行時常量池中,另外在執行期間也能夠將新的常量存放到常量池中,如String的intern()方法。

方法區和執行時常量池在無法滿足內存分配時,也會拋出OutOfMemoryError異常。

(6).直接內存:

直接內存並非java虛擬機執行時數據區的一部分,也不是java虛擬機規範中定義的內存區域。可是在java開發中還是會使用到。

JDK1.4中新引入的NIO(new I/O),引入了一種基於通道(Channel)和緩沖區(Buffer)的I/O方式,能夠使用操作系統本地方法庫直接分配堆外內存,然後通過一個存儲在java堆裏面的DirectByteBuffer對象作為堆外直接內存的引用進行操作,避免了java堆內存和本地直接內存間的數據拷貝,能夠顯著提高性能。

盡管直接內存並不直接收到java虛擬機內存影響。可是假設java虛擬機各個內存區域總和大於物理內存限制,從而導致直接內存不足,動態擴展時也會拋出OutOfMemoryError異常。

java虛擬機內存結構中的程序計數器、虛擬機棧和本地方法棧這三個區域隨線程創建而生,隨線程銷毀而滅,因此這三個區域的內存分配和回收是確定的。java垃圾收集器重點關註的是java虛擬機的堆內存和方法區內存。

java內存結構(執行時數據區域)