天天看點

深入了解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進階特性與最佳實踐》 第二版

關于OopMap - 讨論 - 進階語言虛拟機 - ITeye群組

csdn部落格: java 對象存活分析——引用計數法&可達性分析