1. 程式人生 > >Java記憶體區域與記憶體溢位異常 JVM筆記1

Java記憶體區域與記憶體溢位異常 JVM筆記1

目錄

執行時資料區域

程式計數器

虛擬機器棧

本地方法棧

方法區

直接記憶體

物件的記憶體佈局

物件頭

例項資料

對齊填充

物件的訪問定位


執行時資料區域

JAVA虛擬機器在執行Java程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域。

程式計數器

  • 一塊較小的記憶體空間,可以看作當前執行緒所執行的位元組碼的行號指示器
  • 通過改變這個計數器的值來選取下一條需要執行的位元組碼指令。
  • 每條執行緒都需要一個獨立的程式計數器各條執行緒之間互不影響,獨立儲存,我們稱這類記憶體區域為執行緒私有的記憶體。

虛擬機器棧

  • 也是執行緒私有的,生命週期與執行緒相同。
  • 用來描述Java執行的記憶體模型(區域性變量表,運算元棧,動態連結,方法出口等)
  • 如果執行緒請求的棧深度大於虛擬機器所允許的深度,丟擲StackOverflowError異常
  • 如果虛擬機器棧可以動態擴充套件,擴充套件時無法申請到足夠的記憶體,就會丟擲OutOfMemoryError異常

本地方法棧

  • 執行緒私有
  • 與虛擬機器棧作用類似,不過虛擬機器棧為虛擬機器執行Java方法服務,而本地方法棧為虛擬機器使用到的Native方法服務
  • 也會丟擲StackOverflowError和OutOfMemoryError異常

  • 執行緒共享
  • Java虛擬機器所管理記憶體最大的一塊,在虛擬機器啟動時建立。
  • 用於儲存物件例項,幾乎所有物件例項都在這裡分配記憶體。
  • 是垃圾收集器管理的主要區域
  • 如果堆中沒有記憶體完成例項分配,並且堆也無法擴充套件時,將會丟擲OutOfMemoryError異常

方法區

  • 執行緒共享
  • 用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料
  • 很少出現垃圾回收行為
  • 常量池時方法區的一部分,Class檔案除了又類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編譯器生成的各種字面量和符號引用,這部分內容在類載入後進入方法區的執行時常量池中存放。常量池具有動態性
    ,執行期間也可能將新的常量放入池中,比如String類的intern()方法
  • 無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常

直接記憶體

  • 即本機的記憶體,不是虛擬機器執行時資料區的一部分,但是經常用到。
  • 也可能導致OutOfMemoryError異常,比如為虛擬機器分配的記憶體大於實體記憶體限制。

物件的記憶體佈局

在HotSpot虛擬機器中,物件在記憶體中的儲存的佈局可以分為3塊區域:物件頭(Header)、例項資料(Instance Data)和對其填充(Padding)。

物件頭

HotSpot的物件頭包括兩部分資訊。
第一部分:

  • 儲存物件自身的執行時資料。雜湊碼、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒ID、偏向時間戳等。
  • 長度在32位和64位虛擬機器中(未開啟壓縮指標)中分別為32bit和64bit,官方稱它為“Mark Word”。

第二部分

  • 物件頭另外一部分時型別指標,即物件指向它的類元資料的指標,虛擬機器通過這個指標來確定物件是哪個類的例項
  • 若物件是陣列,那麼在物件頭中還必須有一塊用於記錄陣列長度的資料。

例項資料

  • 是物件真正儲存的有效資訊,也是程式程式碼中所定義的各種型別的欄位內容。
  • HotSpot虛擬機器預設的分配策略為longs/doubles,ints,shorts/chars,bytes/booleans,oops(Ordinary Object Pointers),相同寬度的欄位總是被分配在一起。

對齊填充

  • 並不是必然存在的,也沒有特別含義。
  • 起到佔位符的作用。

物件的訪問定位

建立物件是為了使用物件,我們的Java程式主要通過棧上的reference資料來操作堆上的具體物件。由於reference型別在java虛擬機器規範中只規定了一個指向物件的引用,並沒有定義這個引用應該通過什麼樣的方式區定位、訪問堆中物件的具體位置,所以物件訪問方法方式也是取決於虛擬機器實現而定的。目前主流的訪問方式為控制代碼直接指標兩種。

  • 若是使用控制代碼訪問,Java堆中會劃出一塊記憶體作為控制代碼池,reference中儲存的就是物件的控制代碼地址,控制代碼中包含物件例項資料(在Java堆)與型別資料(在方法區)各自的具體地址資訊
    優點:在物件被移動時只會改變控制代碼中的例項資料指標,而reference本身不需要修改。
  • 若是使用直接指標訪問,Java堆就必須考慮如何放置訪問型別資料的相關資訊,reference中儲存的直接就是物件地址。
    優點:訪問速度更快,節省一次指標定位時間。