JVM內存管理——總結篇

JVM內存管理——總結篇

內存劃分及作用

  • 程序計數器

    1. 線程私有、字節碼行號指示器。
    2. 執行Java方法,計數器記錄的是字節碼指令地址;執行本地(Native)方法時,為空。
  • 本地方法棧
    與虛擬機棧類似,為Native方法服務

  • Java虛擬機棧

    1. 每個方法執行對應一個棧幀,存儲局部變量表、操作數棧、動態連接、方法出口等信息
    2. 局部變量表:存放編譯期可知的基本數據類型、對象引用、返回值地址
    3. 局部變量表以局部變量槽為單位,long和double占兩個槽位,其余一個
    4. 棧幀中的內存大小在編譯期間已經確定
    5. 線程請求的內存大于虛擬機允許的深度,報錯stackoverflowerror;棧拓展時無法申請足夠內存,報錯OutOfMemoryError
  • Java堆

    線程共享、唯一目的存放對象實例

    • 方法區
      存儲類型信息、常量、靜態變量、代碼緩存等

    • 運行時常量池
      編譯期生成的字面量和符號引用

  • 直接內存
    Java堆中的DirectByteBuffer對象對這塊內存直接操作,避免數據在Native和Java堆中來回復制。

常見問題

  • 普通對象的創建過程

    1. 檢測類是否已被加載
      當虛擬機遇到 new 指令時,首先先去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,就執行類加載過程。
    2. 為對象分配內存
      類加載完成以后,虛擬機就開始為對象分配內存,此時所需內存的大小就已經確定了
    3. 為分配空間初始化零值
      保證對象沒有賦初始值也可以使用
    4. 其他設置
      設置對象頭信息,如所屬類、hashcode、gc分代年齡
    5. 執行init方法
      按程序代碼分配初始值
  • Java堆為實例分配內存的方式

    選擇哪種分配方式由Java堆是否規整決定的,而Java堆內存是否規整由垃圾回收器是否帶有空間壓縮整理能力決定的
    Serial、ParNew === > 指針碰撞
    CMS=== >空閑列表

    • 連續空間
      使用指針碰撞方式,移動被占內存和可用空間的指針來分配。多線程發生內存沖突時,利用CAS加失敗重試保證分配;或者本地線程分配緩存(TLAB)方式分配內存

    • 非連續空間
      維護一張列表,記錄可用空間,分配內存更新列表

  • 對象內存布局

    1. 對象頭
      第一部分“Mark Word”:運行時數據,哈希碼、GC分代年齡、鎖狀態
      第二部分:類型指針,指向類的元數據;
    2. 實例數據
    3. 對其填充(因為對象起始地址必須是8字節的整倍數)
  • 對象的兩種訪問定位

    棧中的reference數據引用,引用分為“句柄訪問”、“直接指針訪問”兩種

    • 句柄訪問
      堆中劃分句柄池,句柄中包含對象實例數據和類型數據各自具體地址。優點:對象被移動時,只需改變句柄中實例數據指針
    • 直接訪問
      直接訪問對象地址。優點:少了一次開銷,訪問速度更快
posted @ 2020-07-06 21:43  boardMan  閱讀(...)  評論(...編輯  收藏
色网站直播