1. 程式人生 > >《深入理解Java虛擬機器—JVM高階特性與實踐 周志明 著》之第2章 Java記憶體區域與記憶體溢位異常

《深入理解Java虛擬機器—JVM高階特性與實踐 周志明 著》之第2章 Java記憶體區域與記憶體溢位異常

1、Java虛擬機器所管理的記憶體包括以下幾個執行時資料區域:

2、程式計數器:

         1. 可以看作是當前執行緒所執行的位元組碼的行號指示器,是一塊較小的記憶體空間;

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

         3. Java虛擬機器的多執行緒中,每條執行緒都需要有一個獨立的程式計數器,各條執行緒之間計數器互不影響,獨立儲存;

         4. 如果執行緒正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的Native方法,這個計數器值則為空;

         5. 程式計數器是唯一一個在java虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域;

3、Java虛擬機器棧:

         1. 虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務;

2. 生命週期與執行緒相同,描述的是Java方法執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊。每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程;

         3. 兩種異常狀況:如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲Stack OverflowError異常;如果虛擬機器棧可以動態擴充套件,擴充套件時無法申請到足夠的記憶體,就會丟擲OutOfMemoryError異常;

4、本地方法棧:

         1. 本地方法棧則為虛擬機器使用到的Native方法服務;

         2. 本地方法棧區域也會丟擲StackOverflowError和OutOfMemoryError異常;

5、Java堆:

         1. Java堆是Java虛擬機器所管理的記憶體中最大的一塊,被所有執行緒共享的一塊記憶體區域;

         2. Java堆唯一目的就是存放物件例項,是垃圾收集器管理的主要區域,也被稱為“GC堆;”

3. 如果堆中沒有記憶體完成例項分配,並且堆也無法再擴充套件時,將會丟擲OutOfMemoryError異常;

6、方法區:

         1. 與Java堆一樣,是各個執行緒共享的記憶體區域,用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料;

         2. 當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常;

7、執行時常量池;

         1. 是方法區的一部分,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放;

         2. 當常量池無法再申請到記憶體時會丟擲OutOfMemoryError異常;

8、直接記憶體:

         1. 記憶體區域總和大於實體記憶體限制,也會導致OutOfMemoryError異常;

9、HotSpot虛擬機器物件探祕:

         1. 物件的建立過程:

虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。如果沒有,那必須先執行相應的類載入過程;在類載入檢查通過後,虛擬機器將為新生物件分配記憶體;記憶體分配完成後,虛擬機器需要將分配到的記憶體空間都初始化為零值;

         2. 物件的記憶體佈局:

                   物件在記憶體中儲存的佈局可以分為3塊區域:物件頭、例項資料、對齊填充;

                   物件頭包括兩部分資訊:第一部分用於儲存物件自身的執行時資料;另一部分是型別指標,即物件指向它的類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項;

                   例項資料部分時物件真正儲存的有效資訊,也是程式程式碼中所定義的各種型別的欄位內容;

                   對齊填充僅僅起著佔位符的作用,並不是必然存在的,沒有特別含義;

         3. 物件的訪問定位:

                   通過兩種方式訪問:控制代碼、直接指標;

                   控制代碼方式:Java堆中將會劃分出一塊記憶體來作為控制代碼池,reference中儲存的就是物件的控制代碼地址,而控制代碼中包含了物件例項資料與型別資料各自的具體地址資訊;

                     直接指標訪問:reference中存貯的直接就是物件地址;

兩種方式的比較:

使用控制代碼來訪問的最大好處就是reference中儲存的是穩定的控制代碼地址,在物件移動時只會改變控制代碼中的例項資料指標,而reference本身不需要修改;

使用直接指標訪問方法的最大好處就是速度更快,節省了一次指標定位的時間開銷;