天天看點

Java虛拟機記憶體區域概述1.運作時資料區域2.程式計數器3.Java虛拟機棧4.本地方法棧5.Java堆(重點)6.方法區7.運作時常量池8.直接記憶體9.HotSpot虛拟機對象探秘

1.運作時資料區域

五大部分:虛拟機棧、本地方法棧、程式計數器、堆、方法區

  • 由所有線程共享的資料區:虛拟機棧、本地方法棧、程式計數器
  • 線程隔離的資料區:堆、方法區

2.程式計數器

  • 看作目前線程所執行的位元組碼的行号訓示器
  • 目的:為了線程切換後能恢複到正确的執行位置
  • 線程私有

3.Java虛拟機棧

  • Java方法執行的線程記憶體模型
  • 方法執行時,存儲局部變量表、操作樹棧、動态連接配接、方法出口等資訊
  • 一個方法被調用直至執行完畢的過程,對應Java虛拟機中入棧到出棧的過程
  • 線程私有
虛拟機棧兩類異常情況:
  1. 如果線程請求的棧深度大于虛拟機允許的深度,抛出StackOverflowError異常
  2. 如果虛拟機棧容量可以動态擴充,當棧擴充時無法申請到足夠的記憶體時,抛出OutOfMemoryError異常

Note:目前主流的HotSpot虛拟機 ,不允許動态擴充

是以除非在建立線程申請記憶體時無法得到足夠記憶體而報錯StackOverflowError,否則報錯OutOfMemoryError

4.本地方法棧

  • 與虛拟機棧發揮的作用相似
  • 虛拟機棧 :執行Java方法服務 本地方法棧:為虛拟機使用到的本地方法服務
  • 有的虛拟機(如HotSpot),直接将本地方法棧與虛拟機棧合二為一
  • 線程私有

5.Java堆(重點)

  • 唯一目的:存放對象執行個體,虛拟機管理的記憶體中最大的一塊
由于即時編譯技術的進步,Java對象執行個體都配置設定在堆上不那麼絕對了
  • Java堆是垃圾收集器管理的記憶體區域,稱為GC堆
  • 線程共享
  • 從記憶體配置設定的角度上看,所有線程共享的Java堆中可以劃分出多個線程私有的配置設定緩沖區,以提升對象配置設定時的效率

6.方法區

  • 存儲已經被虛拟機加載的類型資訊、常量、靜态變量、即時編譯器編譯後的代碼緩存等資料
  • 别名“非堆”,為了與Java堆區分開來
  • 方法區的限制非常寬松,除了和Java堆意義不需要連續記憶體、可以選擇固定大小或可擴充外,甚至可以選擇不實作垃圾收集
  • 過去用永久代來實作方法區,現在用原空間來代替
  • 線程共享

7.運作時常量池

  • 方法區的一部分,同樣受限于方法區
  • 常量池表:用于存放編譯器生成的各種字面量和符号引用
  • 類的版本、字段、方法、接口等的描述資訊

8.直接記憶體

  • 并不是虛拟機運作時資料區的一部分,但使用頻繁
  • NIO類,直接使用Native函數庫配置設定堆外記憶體,通過Java堆中的記憶體引用來操作,避免了在Java堆和Native堆中來回複制資料

9.HotSpot虛拟機對象探秘

9.1 對象建立

  1. 首先,檢查指令參數是否能在常量池中定位到一個類的符号引用,并檢查這個符号引用代表的類是否已經被加載、解析和初始化過。
  2. 接下來虛拟機将會為新生對象配置設定記憶體

如果Java堆中記憶體絕對規整,空閑記憶體與已占用記憶體分兩邊,配置設定方式為“指針碰撞”

Java堆内記憶體不規整時,虛拟機必須維護一個清單“空閑清單”,來标記記憶體占用情況

僅僅修改指針所指向的位置來配置設定對象記憶體,在并發情況下也并不線程安全:

兩種解決方案:對配置設定記憶體空間的動作進行同步處理,本地線程配置設定緩存。

  • 記憶體配置設定完成後,虛拟機将分到的記憶體空間都初始化為零
  • 接下來,虛拟機會對對象進行必要的設定。
  • 虛拟機視角上對象産生了,Java程式視角上構造函數開始

9.2 對象的記憶體布局

對象在堆記憶體中的存儲布局三部分:對象頭、執行個體資料、對齊填充

  • 對象頭:1. 用于存儲對象自身運作時資料,如哈希碼,鎖狀态等;

    2. 類型指針,對象指向它的類型元元素的指針

  • 執行個體資料部分:有效字段内容
  • 對齊填充:并不必然存在,沒有特定含義,占位符的左右,必須是8位元組的整數倍

9.3 對象的通路定位

  • 由虛拟機實作而定
  • 主要有使用句柄和直接指針兩種
  • 使用句柄:Java堆中劃分一塊記憶體作為句柄池,存放句柄位址進而間接通路,對象移動時直需要改變句柄位址
  • 直接指針:存儲的就是對象位址,少一次間接通路的開銷
  • 直接指針更快,是HotSpot使用方式

繼續閱讀