java垃圾回收-讀書筆記《深刻理解java虛擬機》

GC須要完成的3件事情

  • 哪些內存須要回收?
  • 何時回收?
  • 如何回收?

判斷對象已死方法(哪些內存須要回收)

  • 引有計數法
    • 給對象添加一個引用計數器
      • 每當有一個地方引用它時,計數加1
      • 當引用失效時,計數減1
    • 計數器爲0的對象就是不可能再被使用的
    • 問題:很難解決對象循環引用
  • 可達性分析法
    • Java中使用方法
    • 基本思路:沒有被GC Roots對象引用鏈引用到的對象
    • Java中,可做爲GC Roots的對象有:
      • 虛擬機棧中引用的對象
        • 棧幀中的本地變量表
        • 即正在執行的方法的局部變量
      • 方法區中類靜態屬性引用的對象
        • 例:類中被static修飾的變量
      • 方法區中常量引用的對象
        • 例:類中被static final修飾的變量
      • 本地方法棧中JNI引用的對象
        • 即通常說的native方法

垃圾回收算法(如何回收)

  • 標記-清除算法(Mark-Sweep)
    • 思路:
      • 首先標記出全部須要回收的對象
      • 在標記完成後統一回收全部被標記的對象
    • 不足:
      • 效率問題,標記和清除兩個過程效率都不高
      • 空間碎片太多,分配較大對象時,沒有足夠大的連續空間,不得不提早觸發另外一次垃圾回收動做
  • 複製算法
    • 思路:
      • 將可用內存按容量劃分爲大小相等的兩塊
      • 每次只使用其中一塊
      • 當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面
      • 而後再把已使用過的內存空間一次清理掉
    • 優勢:
      • 實現簡單,運行高效
      • 每次都是對整個半區進行內存回收
      • 內存配時不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配便可
    • 不足:
      • 將內存縮小爲原來的一半
    • 通常用來回收新生代
      • 將內存分爲一塊較大的Eden空間、兩塊較小的Survivor空間
      • 每次使用Eden和其中一塊Survivor
      • 當回收時,將Eden和Survivor中還存活對象所有複製到另外一塊Survivor中
      • 最後清理掉Eden和剛用過的Survivor空間
      • HotSpot虛擬機默認Eden:Survivor爲8:1
      • 當Survivor空間不夠用時,須要依賴其餘內存(老年代)進行分配擔保
  • 標記-整理算法
    • 思路:
      • 標記過程仍然與「標記-清除」算法同樣
      • 讓全部存活的對象都向一端移動
      • 而後直接清理掉端邊界之外的內存
    • 通常用於老年代
  • 分代收集算法
    • 思路:
      • 根據對象存活週期的不一樣將內存分爲幾塊
    • 通常Java堆分爲兩塊
      • 新生代
        • 每次垃圾收集時都發現有大批對象死去,只有少許存活
        • 選用複製算法
      • 老年代
        • 對象存活率高
        • 沒有額外空間對它進行分配擔保
        • 使用「標記-清理」或「標記-整理」進行回收

HotSpot的算法實現

垃圾收集器

內存分配與回收策略

  • 對象優先在Eden分配
  • 大對象直接進入老年代
    • 應當避免「朝生夕滅」的大對象,容易致使頻繁GC
  • 長期存活的對象將進入老年代
  • 動態對象年齡斷定
  • 空間分配擔保
掃一掃 關注個人公衆號 【老羅開發】
相關文章
相關標籤/搜索