1. 程式人生 > >JAVA 記憶體區域和記憶體溢位異常

JAVA 記憶體區域和記憶體溢位異常

一、執行時資料區域

概念

JAVA虛擬機器在執行JAVA程式的過程中會把它管理的記憶體劃分若干個不同的資料區域。有著各自的用途,以及建立和銷燬時間。

資料區域:

1) 程式計數器

A當前執行緒所執行的位元組碼行號指示器。位元組碼直譯器工作時就是通過改變這個計數器的值來選取下一個需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成。

B每條執行緒都有一個獨立的程式計數器,各執行緒互不影響,獨自儲存,該區域是執行緒私有的記憶體。

C、執行緒執行的是Java方法,計數器存的是虛擬機器位元組碼指令的地址;執行的是Native方法,計數器的值為空。

D、唯一一個在

java虛擬機器中沒有規定任何OutOfMemoryError情況的區域。

2) JAVA虛擬機器棧

A、描述的是Java方法(位元組碼)執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀,用於儲存區域性變量表(存放編譯期可預知的各種基本型別、物件引用)、運算元棧、動態連結、方法出口等資訊。每個方法從呼叫直到執行完成的過程,就會對應一個棧幀在虛擬機器棧中入棧到出棧的過程。

B、每條執行緒都有一個獨立的JAVA虛擬機器棧,各執行緒互不影響,獨自儲存,該區域是執行緒私有的記憶體。

C、兩種異常情況:如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError;如果虛擬機器棧可以動態擴充套件

(大部分虛擬機器支援),擴充套件時無法申請到足夠的記憶體,將丟擲OutOfMemoryError.

3) 本地方法棧

A、描述的是Native方法執行的記憶體模型。與Java虛擬機器棧類似。

B、HotSpot虛擬機器,本地方法棧和Java虛擬機器棧合二為一

C、兩種異常情況:如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError;如果虛擬機器棧可以動態擴充套件(大部分虛擬機器支援),擴充套件時無法申請到足夠的記憶體,將丟擲OutOfMemoryError.

4) JAVA

A、大部分物件實列以及陣列的記憶體分佈區域。唯一目的就是存放物件的實列。

B、執行緒共享的記憶體區域

,在虛擬機器啟動的時候建立。垃圾收集器管理的主要區域。

C、Java堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可,就像我們的磁碟空間一樣。

D、異常情況:如果在堆中沒有記憶體完成例項完成分配,並且堆無法再擴充套件時,將會丟擲OutOfMemoryError.

5) 方法區

A、用於儲存已經被虛擬機器載入的內資訊、常量、靜態變數、即時編譯後的程式碼等資料。別名:非堆。

B、當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError.

C包含執行時常量池。用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。具備動態性,執行期間可將新的常量放入池中。如Stringintern().

6) 直接記憶體

A、不屬於執行時資料區域一部分,但頻繁的使用。

B、JDK1.4中新加入NIO,引入一種基於通道(channel)和快取區(Buffer)I/O方式,

它可以使用Native函式庫直接分配堆外記憶體,然後儲存在Java堆中的DirectByteBuffer物件作為這塊記憶體的引用進行操作,提高效能。

C、受到本機總記憶體(包括RAM以及SWAP區或者分頁檔案)大小以及處理器定址空間的限制,導致動態擴展出現OutOfMemoryErro.

二、虛擬機器堆中物件分配、佈局和訪問

1、物件的建立

new Object時,首先檢查這個指令的引數是否能在方法區的常量池中定位到這個類的符號引用,並檢查這個符號引用代表的類是否已經載入、解析、初始化過。如果沒有,就先執行相應的類載入過程。接下來虛擬機器為新生物件分配記憶體,然後將分配的記憶體空間進行初始化零值,接下來,對物件設定物件頭(Object Header).列如這個物件是哪個類的實列、如何才能找到類的元資料資訊、物件的雜湊碼,物件的GC分代年齡等資訊,最後執行init方法,對資料進行初始化

2、物件的記憶體佈局

分為三個區域:物件頭、例項資料和對齊填充

物件頭:包含兩部分資訊,第一部分用於儲存物件自身的執行時資料,如雜湊碼,GC分代年裡、鎖狀態標誌、執行緒持有的鎖、偏向鎖ID、偏向時間戳等。第二部分是型別指標,即物件指向它的類資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項。

例項資料:程式程式碼中所定義的各種型別的欄位內容,包含父類繼承下來的,以及子類定義的。儲存順序受虛擬機器分配策略引數和欄位在java原始碼中定義順序影響。

對齊填充:不是必然存在,僅僅佔位符作用,當物件例項資料不符沒有對齊時,需要通過對齊填充補全。

3、物件的訪問定位

主流訪問方式:控制代碼和直接指標

控制代碼:Java堆劃分一塊記憶體作為控制代碼池,引用中儲存的就是物件的控制代碼地址,而控制代碼中包含了物件例項資料與型別資料各自的具體地址資訊。

指標訪問:引用中儲存的直接就是物件地址。

使用控制代碼訪問最大的好處就是引用中儲存的都是穩定的控制代碼地址,在物件移動時會改變控制代碼中的例項資料指標,而引用本身不需要修改。使用直接指標訪問方式最大好處就是速度更快,節省一次指標定位的時間開銷。HotSpot使用的就是後者。