JVM內存管理——總結篇

JVM內存管理——總結篇

內存劃分及做用

  • 程序計數器緩存

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

  • Java虛擬機棧jvm

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

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

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

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

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

常見問題

  • 普通對象的建立過程內存

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

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

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

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

  • 對象內存佈局

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

    棧中的reference數據引用,引用分爲「句柄訪問」、「直接指針訪問」兩種

    • 句柄訪問
      堆中劃分句柄池,句柄中包含對象實例數據和類型數據各自具體地址。優勢:對象被移動時,只需改變句柄中實例數據指針
    • 直接訪問 直接訪問對象地址。優勢:少了一次開銷,訪問速度更快
相關文章
相關標籤/搜索