1. 程式人生 > >JAVA執行時資料區域:記憶體區域與記憶體溢位異常

JAVA執行時資料區域:記憶體區域與記憶體溢位異常

方法區(Method Area)

  1. 儲存內容用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。
  2. 與執行緒的關係 各個執行緒共享該記憶體區域
  3. 異常 這區域的記憶體回收目標主要是針對常量池的回收和對型別的解除安裝。當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常。
  4. 執行時常量池
    執行時常量池(Runtime Constant Pool)是方法區的一部分。Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池(Constant Pool Table:注意常量池才是class檔案中的內容,不是執行時常量池),用於存放
    編譯期生成的各種字面量和符號引用(執行期也可以將值放入執行時常量池中),這部分內容將在類載入後進入方法區的執行時常量池中存放。執行時常量池是方法區的一部分,自然受到方法區記憶體的限制,當常量池無法再申請到記憶體時,將丟擲OutMemoryError異常。

    JVM堆(Heap)

  1. 儲存內容此記憶體區域的唯一目的就是存放物件例項(物件例項以及陣列都要在堆上分配)。java堆是垃圾收集器管理的主要區域,也被稱為GC堆(Garbage Collection)
  2. 與執行緒的關係 Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。執行緒共享的Java堆中可能劃分出多個執行緒私有的分配緩衝區(Thread Local Allocation Buffer,TLAB即把記憶體分配的動作按照執行緒劃分在不同的空間之中進行,即每個執行緒在Java堆中預先分配一小塊記憶體,稱為本地執行緒分配緩衝。哪個執行緒要分配記憶體,就在哪個執行緒的TLAB上分配,只有TLAB用完並分配新的TLAB時,才需要同步鎖定。)
    ,不論如何劃分,此記憶體區域都是儲存物件例項。
  3. 異常Java堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可。如果在堆中沒有記憶體完成例項分配,並且堆也無法再擴充套件時,將會丟擲OutOfMemoryError異常。
  4. 將java堆分為新生代和年老代,方便根據各個年代來進行物件的回收。
  5. 堆記憶體的分配:通過-Xmx和-Xms控制

    程式計數器(pc:Program Counter Register

執行緒私有---為了執行緒切換後能恢復到正確的位置,每條執行緒都需要有一個獨立的程式計數器,各條執行緒之間計數器互不影響,位元組碼直譯器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令。

JVM棧(JVM stack)

  1. 儲存內容
    JVM棧描述的是java方法執行的記憶體模型,每個方法在執行的同時都會建立一個棧幀(Stack Frame:方法執行時的基礎資料結構)用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊,每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程。區域性變量表存放了編譯期可知的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(reference型別)和returnAddress型別(指向了一條位元組碼指令的地址),其中64位長度的long和double型別的資料會佔用2個區域性變數空間(Slot),其餘的資料型別只佔用1個。區域性變量表所需的記憶體空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的區域性變數空間是完全確定的,在方法執行期間不會改變區域性變量表的大小。
  2. 與執行緒的關係
    執行緒私有的,生命週期與執行緒相同
  3. 異常
    如果執行緒請求的棧深度大於虛擬機器所允許的深度,將會丟擲StackOverflowError異常。 如果虛擬機器棧可以動態擴充套件,如果擴充套件時無法申請到足夠的記憶體,就會丟擲OutOfMemoryError 異常。

直接記憶體(Direct  Memory)

直接記憶體並不是虛擬機器執行時資料區的一部分,也不是Java虛擬機器規範中定義的記憶體區域。在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩衝區(Buffer)的I/O方式,可以使用Native函式庫直接分配堆外記憶體,然後通過一個儲存在Java堆中的DirectByteBuffer物件作為這塊記憶體的引用進行操作,避免了在java堆和Native堆中來回複製資料。會出現OutOfMemoryError異常。