1. 程式人生 > >深入理解JVM——引用計數法和可達性分析演算法(理解)

深入理解JVM——引用計數法和可達性分析演算法(理解)

引言

JVM中的堆和方法區主要用來存放物件(方法區中也儲存了一些靜態變數和全域性變數等資訊),那麼我們要使用GC演算法對其進行回收時首先要考慮的就是該物件是否應該被回收。即判斷該物件是否還有其他的引用或者關聯使得該物件處於存活狀態,我們需要將不在存活狀態的物件標記出,以便GC回收。

引用計數法

在物件頭處維護一個counter,每增加一次對該物件的引用計數器自加,如果對該物件的引用失聯,則計數器自減。當counter為0時,表明該物件已經被廢棄,不處於存活狀態。這種方式一方面無法區分軟、虛、弱、強引用類別。另一方面,會造成死鎖,假設兩個物件相互引用始終無法釋放counter,永遠不能GC。

可達性分析演算法

通過一系列為GC Roots的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引用鏈相連時,則證明該物件是不可用的。如果物件在進行可行性分析後發現沒有與GC Roots相連的引用鏈,也不會理解死亡。它會暫時被標記上並且進行一次篩選,篩選的條件是是否與必要執行finalize()方法。如果被判定有必要執行finaliza()方法,就會進入F-Queue佇列中,並有一個虛擬機器自動建立的、低優先順序的執行緒去執行它。稍後GC將對F-Queue中的物件進行第二次小規模標記。如果這時還是沒有新的關聯出現,那基本上就真的被回收了。

可達性分析演算法是通過列舉根節點來實現的,最重要的問題是

GC停頓。為了確保一致性(即所有物件之間的關係是確定下來的)而導致GC進行時必須進行停頓。在HotSpot的中,使用OopMap的資料結構儲存特定位置上的除錯資訊,儲存棧上那個位置原來是什麼東西,這個資訊是在JIT編譯時跟機器碼一起產生的。因為只有編譯器知道原始碼跟產生的程式碼的對應關係。 這樣,GC在掃描時就可以得知這些資訊了。這樣做的目的是使HotSpot能夠快速準確的完成GC Roots列舉,以期望減少GC停頓所帶來的影響。HotSpot沒有在所有的指令生成OopMap,所以只是在“特定位置”記錄這些資訊,這些位置就是安全點。程式執行時並非在所有的位置上都能停頓下來GC,只有在到達安全點時才能暫停。安全點選取基本上是以“是否讓程式長時間執行的特徵”選定。此外,HotSpot虛擬機器在安全點的基礎上還增加了安全區域的概念,安全區域是安全點的擴充套件。在一段安全區域中能夠實現安全點不能達成的效果。

參考文獻:

《深入理解Java虛擬機器——JVM高階特性與最佳實踐》 第二版