天天看點

Java虛拟機如何判定對象可以被回收及GCRoots包含哪些對象

問題

Java虛拟機有自己的一套記憶體管理機制,包含了多種垃圾回收算法,并且有多種垃圾回收器來使用這些算法(本文不描述)。但無論是使用哪種垃圾回收算法,都有個前提,就是要判定這個對象是可以被回收的,才可以執行垃圾回收。

那麼,Java虛拟機是如何判定對象是可以被回收的呢?

我們常聽到的GC Roots具體是指什麼呢?

可達性分析算法

目前主流的商用程式語言(Java、C#)的記憶體管理子系統都是通過可達性分析(Reachability Analysis)算法來判定對象是否存活的。這個算法的基本思路就是通過一系列稱為“GC Roots”的根對象作為起始節點集,從這些節點開始,根據引用關系向下搜尋,搜尋過程中走過的路徑成為“引用鍊”(Reference Chain),如果某個對象到GC Roots間沒有任何引用鍊相連,或者用圖論的話來說就是從GC Roots到這個對象不可達時,則證明此對象是不可能再被使用的。

另外還有一種叫做“引用計數法”的算法,也是用來判定對象使用狀态的,不過Java虛拟機沒有使用引用計數法,這裡不再贅述。

也就是說,Java虛拟機通過可達性分析算法來判定對象能否被回收。

GC Roots

在Java技術體系裡面,固定可以作為GC Roots的對象包括以下幾種:

  • 在虛拟機棧(棧幀中的本地變量表)中引用的對象,譬如目前正在運作的方法所用到的參數、局部變量、臨時變量等。
  • 在方法區中靜态屬性引用的對象,譬如Java類的引用類型靜态變量。
  • 在方法區中常量引用的對象,譬如字元串常量池(String Table)裡的引用。
  • 在本地方法棧中JNI(即通常所說的Native方法)引用的對象。
  • Java虛拟機内部的引用,如基本資料類型對象的Class對象,一些常駐的異常對象(如NullPointException、OutOfMemoryError)等,還有系統類加載器。
  • 所有被同步鎖(synchronized關鍵字)持有的對象。
  • 反應Java虛拟機内部情況的JMXBean、JVMTI中注冊的回調、本地代碼緩存等。

除了上述這些固定的GC Roots集合外,根據使用者所選用的垃圾收集器及目前回收的記憶體區域不同,還可以有其他對象“臨時性”地加入,共同建構完整的GC Roots集合。

是以,固定可以作為GC Roots的對象是上面這幾種。