天天看點

老生常談的java垃圾回收機制

一、确定被回收的對象

1. 引用計數(Reference Counting)

給對象添加一個引用計數器,當該對象被其他對象引用時,計數器加一;引用失效時計數器減一;引用數為0的對象就是需要被回收的對象。

這樣的算法實作簡單,但也存在弊端,比如有兩個對象互相引用,但卻沒有其他任何地方引用它們,它們應當被視為“垃圾”,但他們的引用計數器并不為0;

2.可達性分析(Reachability Analysis)

選擇一系列對象作為起始點(GC Roots),從這些節點開始進行DFS,搜尋過的路徑被稱為引用鍊,若某個對象未處在任何引用鍊中,即該對象不可達,那麼就認為這個對象是可被回收的;

GC Root可以是:

  • 虛拟機棧中引用的對象,即函數内局部變量所引用的對象;
  • 方法區中類靜态屬性引用的對象;
  • 方法區中常量引用的對象;
  • 本地方法棧中引用的對象;

3. 對象的finalize方法

當一個對象在某一次可達性分析中,被标記為不可達,那麼它的finalize方法就可能被調用,前提是:

  • 該對象的finalize方法被覆寫;
  • 該對象的finalize方法為被執行過;

若滿足以上兩個條件,該對象會被加入到F-Queue中,由一個Finalizer線程執行;

虛拟機并不保證隊列中的對象的finalize方法一定會被執行,等到第二次标記到來時,仍然被标記為不可達的對象将會在不遠的将來被回收;

不過在項目代碼中,finalizer最好不要被重寫;

4.方法區的回收

方法區的垃圾回收主要包括:廢棄常量和無用的類;

廢棄常量顧名思義是指沒有被用到的常量,即目前程序中沒有任何一個對象引用了該常量;

判定一個類是垃圾就比較麻煩:

  • 首先,堆上不存在任何該類的執行個體;
  • 該類的classloader被回收;
  • 類對應的對象沒有被引用,無法通過反射調用該類的方法;

二、垃圾回收算法

1. 标記-清除(Mark-Sweep)

首先标記出所有需要被回收的對象,然後統一回收;

它的不足在于效率較低且會産生大量的記憶體碎片;

2. 複制算法(Copying)

将記憶體分為兩塊,每次隻使用其中一塊,進行回收時,将仍存活的對象複制到另半塊記憶體中,然後清理已使用的半塊記憶體;

優點是效率高且沒有碎片,缺點是浪費記憶體;

複制算法常被用于新生代的記憶體回收。由于在實際場景中,新生代的對象大多會在GC中被回收,因而備用記憶體可以小一些;實際的做法是将記憶體分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和一塊Survivor,GC時将存活對象複制到另一塊Survivor空間中;Eden與Survivor的比例為8:1,浪費的空間為10%,尚可接受;當Survivor空間不夠用時,可以使用老年代空間進行配置設定擔保;

3. 标記-整理(Mark-Compact)

将所有存活對象移到空間的一端,然後将區域外的空間清理;

4.分代收集

新生代對象“朝生夕死”,使用複制算法;老年代對象存活率高,使用标記-整理或标記清除;

三、保證GC的效率

1.使用OopMap找到GC Root

OopMap是一個記錄了對象引用在Java堆棧中的位置的資料結構;

在GC時,GC線程就不需要掃描整個方法區,可以友善的知道每個對象的位置,進而快速完成根節點枚舉;

2.安全點(Safe Point)

程式運作期間導緻引用變化的指令非常多,每次變化都生成新的OopMap顯然是不現實的;事實上,隻有當線程運作到安全點(Safepoint)時才停下來開始生成OopMap、進行GC;

安全點的線程同步,即讓所有線程同時停在最近的安全點:

  • 搶先式中斷:GC發生時,讓所有線程暫停,如果暫停的地方不在安全點上,就恢複線程,讓它停到最近的安全點上;
  • 主動式中斷:設定一個中斷标志,線程執行時不斷地輪詢這個标志,若發現标志為真則把自己中斷挂起,标志設定在安全點上;

實際一般用主動式中斷;

3.安全區域(Safe Region)

安全點的不足在于,若線程處于Blocked或Waiting狀态,那麼該線程就無法響應JVM的中斷請求,停到安全點上;

安全區域(Safe Region)被用來解決這個問題。安全區域是引用關系不會發生變化的一段代碼片段,在這個區域的任意位置開始GC都是安全的。當線程離開Safe Region之前,需要檢查系統是否已經完成了GC,若否,則需要等待完成。Safe Region相當于拓寬了安全點,如果說線程在安全區域内Blocked那麼GC還是能正常進行的。

參考

  • 《深入了解Java虛拟機(第2版)》 周志明
  • What does Oop Maps means in Hotspot VM exactly