1. 程式人生 > 其它 >jvm垃圾收集器詳解

jvm垃圾收集器詳解

1. 簡介

垃圾收集器雖然從Serial -> Parallel->ParNew->CMS->G1->ZGC一步步演化,但是新的垃圾收集器不一定就適合所有場景,從垃圾收集的發展程序的可以看出,垃圾收集器的演化無非因為一下幾點:

  • 貼合當下的硬體,能夠更友好的使用硬體資源
  • 減少STW(Stop The World)的時間,提高使用者體驗

2. 基本概念

2.1 jvm記憶體模型

  • 本地方法棧: native方法
  • 棧:一個方法對應一塊棧幀記憶體空間,主要儲存區域性變量表、運算元棧、動態連結、方法出口
  • 程式計數器:每一個棧都有自己的程式計數器,使用者恢復現場
  • 堆:記憶體分配和垃圾回收的主要場所
  • 方法區:執行時常量池,主要儲存元空間、常量、靜態變數、類資訊

2.2 物件記憶體分配流程

  • 物件逃逸分析:當一個物件在方法中被定義後,沒有被外部方法引用
    • 方法內部的物件,可以直接分配在棧的,但是太大了也只能放在堆中
    • 如果物件不會逃逸可以將該物件在棧上分配記憶體,這樣該物件所佔用的記憶體空間就可以隨棧幀出棧而銷燬,就減輕了垃圾回收的壓力
    • 棧上分配依賴於逃逸分析和標量替換
  • 標量替換:標量指不可被進一步分解的量,而JAVA的基本資料型別就是標量
    • 確認物件不逃逸,將物件的成員變數拆分成若干個被這個方法使用的成員變數替換

2.2 垃圾查詢演算法

  • 引用計數法: 效率高,無法解決迴圈引用的問題(基本不用)
  • 可達性分析法:將“GC Roots” 物件作為起點,從這些節點開始向下搜尋引用的物件,找到的物件都標記為非垃圾物件,其餘未標記的 物件都是垃圾物件
  • 根節點(root)
    • 執行緒棧的本地變數
    • 靜態變數
    • 本地方法棧的變數

2.3 垃圾收集演算法

  • 分代收集理論
    • 根據存活週期不同將記憶體分為幾塊
    • 新生代每次收集都會有大量的物件死亡(一般採用複製演算法)
    • 老年代的物件存活的機率比較大(一般採用標記整理或者標記清除)
  • 複製演算法:將記憶體分為大小相同的兩塊,每次使用一塊,當一塊記憶體使用完後,就將還存活的物件複製到另一塊,清理掉當前的塊記憶體
    • 優點:不會產生記憶體碎片,效率高
    • 缺點:記憶體被分割為兩份,佔用記憶體較多
  • 標記清除演算法:標記存活的物件,清除沒有被標記的物件(會造成大量的記憶體碎片,最後肯定會進行一次整理演算法)
    • 優點:記憶體佔用低
    • 缺點:效率不高,容易使記憶體碎片化
  • 標記整理演算法:標記存活的物件,讓所有存活的物件向一端移動,然後直接清理掉端邊界以外的記憶體
    • 優點:記憶體佔用低
    • 缺點:效率不高,比清除演算法還要低,清除演算法會將多次碎片記憶體進行一次整理

3. 垃圾收集器

  • 黑色相連: 表示可以相互配合使用
  • 紅色相連:表示在最後可能會轉變成另外一種方式回收

3.1 Serial

3.2 Parallel

3.3 ParNew

3.4 CMS

3.5 G1

3.6 ZGC