天天看點

JVM-記憶體區域-運作時資料區域(一)

文章目錄

      • 運作時資料區域
        • 程式計數器
        • 虛拟機棧
        • JAVA堆
        • 方法區
          • 運作時常量池
      • 直接記憶體

運作時資料區域

程式計數器

  1. 程式計數器是一塊較小的記憶體空間,它可以看作是目前線程所執行的位元組碼的行号指令器。
  2. 在JAVA的概念模型中,位元組碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,它是程式控制流的訓示器,分支,循環,跳轉,異常處理,線程恢複等基礎功能都需要依賴這個計數器來完成。
  • 線程私有:

    JAVA

    虛拟機的多線程都是通過輪流切換,配置設定處理器執行時間的方式來實作的。在任何一個時刻,一個處理器都隻會執行一條線程中的指令。因為,為了線程切換後能夠恢複到正确的執行位置,每個線程都需要一個獨立的程式計數器,各個線程之前計數器互不影響,獨立存儲,我們稱這類記憶體為線程私有的記憶體。
  • 如果線程正在執行的是

    JAVA

    方法,這個計數器記錄的是正在執行的虛拟機位元組碼指令的位址;如果正在執行的是本地(

    Native

    )方法,這個計數器則為空。
  • 此記憶體區域是唯一一個沒有在《JAVA虛拟機規範》中沒有規定任何

    OutOfMemoryError

    情況的區域。

虛拟機棧

  1. 線程私有,生命周期和線程相同。虛拟機棧描述的是JAVA方法執行的線程記憶體模型:每個方法執行的時候,虛拟機都會同步建立一個棧幀用于存儲局部變量表,操作數棧,動态連接配接,方法出口等資訊。每個方法被調用直至執行完畢的過程,就對應一個棧幀在虛拟機從入棧到出棧的過程。
  2. 局部變量表存放了編譯器可知的各種

    JAVA

    基本資料類型和對象引用類型。
  • 對象引用類型(

    reference

    類型),并不等同于對象本身,可能是指向對象起始位址的引用指針,也有可能是指向一個代表對象的句柄或者其他與此對象相關的位置。
  • rerurnAddress

    類型。指向了一條位元組碼指令的位址。
  • 資料類型在局部變量表中以局部變量槽來表示,其中64位的

    long

    double

    會占據倆個變量槽。
  • 局部變量表所需的記憶體空間在編譯期間完成配置設定,在方法期間不會改變局部變量表的大小。大小指的是槽的數量。
  • 在《虛拟機規範》中,對這塊記憶體區域定義了倆種異常。
    • 如果線程請求的深度大于虛拟機允許的深度,

      StackOverFlowError

    • 如果虛拟機棧容量可以動态擴充,當棧無法申請到足夠的記憶體。

      OutOfMemoryError

JAVA堆

  1. 堆是虛拟機所管理的記憶體中最大的一塊區域,被所有線程共享。在啟動時建立,唯一目的是存放對象執行個體,幾乎所有的對象執行個體都在這裡配置設定記憶體。
  2. 堆是垃圾處理器管理的記憶體區域,是以也被成為GC堆。
  • 堆可以處于實體上的不連續的記憶體空間中,但在邏輯上它應該被視為是連續的。
  • 堆的大小可以固定,可以動态擴充。(

    -Xmx

    -Xms

    )。
  • 堆如果沒有完成記憶體執行個體配置設定,并且堆也無法再擴充時。

    OutOfMemoryError

方法區

  1. 同堆一樣,線程共享的記憶體區域,用于存儲已被虛拟機加載的類型資訊,常量,靜态變量,即時編譯器編譯後的代碼緩存等資料。
  2. 永久代的概念在jdk8之後,移到了元空間。
  • 垃圾回收行為在這塊區域出現的較少,記憶體回收目标主要是針對常量池的回收和對類型的解除安裝。
  • 如果方法區無法滿足新的記憶體配置設定需求時。

    OutOfMemoryError

運作時常量池
  1. 是方法區的一部分。Class檔案中除了有類的版本,字段,方法,接口等描述資訊外,還有一項資訊是常量池表,用于存放編譯期生成的各種字面量與符号引用,這部分内容将在類加載後存放到方法區的運作時常量池中。
  2. 運作時常量池相對于Class檔案常量池的另外一個重要特征就是具有動态性,JAVA語言并不要求常量一定隻有編譯器才能産生,運作期間也可以将新的常量放入池中,這種特征被開發人員利用比較多的便是

    String

    類的

    intern()

    方法。
  • 當常量池無法再申請到記憶體時。OutOfMemoryError

直接記憶體

  1. JDK1.4

    引入了

    NIO

    的概念,這種是基于管道的

    I/O

    方式,它可以使用

    Native

    函數直接配置設定堆外記憶體,然後通過一個存儲在

    JAVA堆

    裡面的

    DirectByteBuffer

    對象作為這塊記憶體的引用進行操作。能夠在一些場景中顯著提高性能,避免了在

    JAVA

    堆和

    Native

    堆來回複制資料。
  2. 不會受到虛拟機記憶體影響,但受到總記憶體影響,如果各區域記憶體大于總記憶體,

    OutOfMemoryError