Java8-JVM內存區域划分白話解讀


前言

java作為一款能夠自動管理內存的語言,與傳統的c/c++語言相比有着自己獨特的優勢。雖然我們無需去管理內存,但為了防范可能發生的異常,我們需要對java內部數據如何存儲有一定了解,已應對突發問題,寫出更好的程序

JVM對運行時程序內存的划分

java程序在被編譯成字節碼后,由JVM執行,執行期間產生的所有數據,會被分門別類的存儲在JVM預設好的區域里,具體情況如下所示

java6時方法區還屬於JVM管理的內存,那時俗稱為“永久代”,負責存儲:被虛擬機加載的類型信息、方法信息、常量(包括字符串常量)、靜態變量等等

java7時把永久代里的字符串常量池、靜態變量移動到了堆中

java8廢除永久代,改用元空間來實現方法區,原來java7中永久代的剩余內容移動到元空間中

以下為java8的內存分布圖

Tips:紅色是線程共享的,黃色是線程私有的

接下來我們着重討論Java8中的內存分布情況

JVM管理的內存

這部分內存在JVM中,由JVM直接分配,初始大小、最大大小都可以由JVM進行配置

程序計數器

是一段較小的內存空間,用於告訴字節碼解釋器下一條執行哪一個字節碼指令。是唯一一個在《java虛擬機規范》沒有規定任何OutOfMemoryError的區域

每條線程必須有獨立的程序計數器,以確保切換線程時,線程可以在正確的位置繼續執行字節碼

Tips:當執行Native方法時,計數器值為空(undefined)


虛擬機棧

我們平常俗稱的棧指的就是虛擬機棧,用來描述和存儲Java方法的內存模型。里面的數據生命周期在編譯時就已經確定了,比如局部變量方法調用結束就該釋放,內存很容易管理,所以並不是很依賴GC

具體行為:

每當執行一個方法時,JVM就會創建一個棧幀放進虛擬機棧中

棧幀的內容包括但不限於:

  1. 局部變量表(也包括形參)
    • 八大基本數據類型
    • 引用類型(直接指針或者句柄,由具體的JVM實現決定)
    • returnAddress類型 (用於方法結束回到原來的字節碼位置繼續執行)
  2. 操作數棧
    • 開始時是空的,運行后逐漸入棧出棧,比如算數運算就是操作數棧進行的
  3. 動態連接
  4. 方法出口

直到方法執行結束,JVM就會將此方法的棧幀出棧

顯然,如果多個線程共用同一虛擬機棧,會出現某個線程的方法還沒執行完畢,又被另一線程的棧幀入棧,破壞了方法數據結構。所以虛擬機棧是線程私有的

returnAddress作用

用於執行完方法后回到調用方法的位置繼續往下執行

當一個棧幀入棧時,returnAddress保存當前程序計數器的值,即當前字節碼位置,然后開始執行方法,方法執行結束后,用returnAddress的值恢復程序計數器,即回到調用方法時的字節碼位置


本地方法棧

幾乎與虛擬機棧一樣的作用,其區別是,本地方法棧為本地Native方法服務,通常是本地的C/C++庫的方法,而虛擬機棧是為java方法服務的


堆區

通常是JVM中最大的內存區域,也是垃圾收集器GC最經常光顧的區域,里面的數據生命周期無法在編譯時確定,需要GC來幫助判斷是否是“死亡變量”,以回收沒必要的內存。

存儲的內容:

  1. 對象的實例
  2. 數組
  3. 字符串常量池
    • 物理上在堆區,邏輯上是方法區的內容
  4. 靜態變量
    • 物理上在堆區,邏輯上是方法區的內容

本地內存

默認情況使用大小只受限於本地內存的實際大小

但我們任可以通過JVM配置限制使用大小

這里面的數據一般不經常變動,存放在這里被JVM間接管理較為合適(間接管理速度肯定比JVM內部的慢些)

方法區(元空間)

java8使用元空間來實現的方法區,《Java虛擬機規范》中方法區為堆區的邏輯部分,堆中的對象依靠方法區存儲的類信息來生成實例

存儲的內容:

  1. 運行時常量池
    • 字面量
    • 符號引用
  2. 類信息
    • 類型
      • 完整名
      • 修飾符
      • 父類、接口信息
      • 名稱
      • 類型
    • 方法
      • 名稱
      • 參數
      • 返回值
      • 字節碼

以上包含了一些有代表性的內容,並不代表方法區存儲的全部內容


直接內存

此部分並不常用,至少對我目前來說。

在jdk1.4中加入了NIO(New Input/Putput)類,引入了一種基於通道(channel)與緩沖區(buffer)的新IO方式,它可以使用native函數直接分配堆外內存,然后通過存儲在java堆中的DirectByteBuffer對象作為這塊內存的引用進行操作,這樣可以在一些場景下大大提高IO性能,避免了在java堆和native堆來回復制數據。--《深入理解java虛擬機》



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM