1. 程式人生 > >一步一步學JVM-垃圾回收

一步一步學JVM-垃圾回收

-- 覆蓋 不可達 建立 class對象 如果 而且 節點 棧幀

  垃圾回收器在對對象進行回收前,首先要判斷對象是否還“活著”。判斷方法有以下兩種

引用計數法

給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1。當引用失效時,計數器值就減1。任何時刻計數器為0的兌現就是不可能再被使用的。

引用計數法的實現簡單,判斷效率也高,也有一些比較著名的應用案例。但是在Java虛擬機裏面沒有選用引用計數算法來管理內存,其中最主要的原因是它很難解決對象之間相互引用的問題。

如下圖所示,對象A引用對象B,而對象B和C又相互引用。如果對象A對對象的B的引用消除,那麽對象B和C就相互引用。通過引用計數法就無法回收B和C兩個對象。

可達性分析算法

該算法的基本思路就是通過一系列成為“GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索過程中的路徑成為旖旎永聯,當一個對象到GC Roots沒有任何引用鏈時,則證明此對象是不可用的,所以它們將會被判定為是可回收的對象。

在Java語言中,可作為GC Roots的對象包括以下幾種

1、 虛擬機棧(棧幀中的本地變量表)中引用的對象

2、 方法區中類靜態屬性引用的對象

3、 方法區中常量引用的對象

4、 本地方法棧中JNI(一般說的Native方法)引用的對象

對象的回收

即使在可達性分析算法中不可達的對象,也並非“非死不可”的,這時候它們處於“緩刑”階段。一個對象的真正死亡,至少要經歷兩個標記過程:如果對象在進行可達性分析後發現沒有與GC Roots相連接的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機調用過,虛擬機將這兩種情況視為“沒有必要執行”。

如果這個對象被判定為有必要執行finalize()方法,那麽這個對象會被防止在一個叫做F-Queue的隊列中,並在稍後由一個虛擬機自動建立的、低優先級的Finalizer線程去執行它,但並不承諾會等待它運行結束,這樣做的原因是,如果一個對象在finalize方法中執行的很慢,或者產生了死循環,將很可能到值F-Queue隊列中的其他對象永久處於等待,甚至導致真個內存回收系統崩潰。

Finalize()方法是對象逃脫死亡的最後一次機會,稍後GC將對F-Queue中的對象進行第二次小規模標記,如果對象要在finalize()中成功拯救自己-----只需要重新與因用力按上的任何一個對象建立關聯即,比如把自己賦值給某個類變量或者對象的成員變量,那在第二次標記時它將被移出“即將回收”的集合;如果對象這時候還沒有逃脫那基本上就真的被回收了。

永久代的回收

永久代的垃圾收集主要回收兩部分內容:廢棄常量和無用的類。回收廢棄常量與回收Java堆中的對象非常類似。假如一個字符串“abc”已經進入了常量池中,但是當前系統沒有任何一個String對象是叫做“abc”的,換句話說,就是沒有任何String對象引用常量池中的“abc”常量,也沒有任何地方引用這個字面量,如果此時發生垃圾回收,而且必要的話,這個“abc”常量就會被系統清理出常量池。

對“無用的類”的回收

  類要同時滿足一下3個條件才能算是“無用的類”。

  1、 該類所有的實例都已經被回收

  2、 加載該類的ClassLoader已經被回收

  3、 該類隊形的Class對象沒有被任何地方引用,無法在任何地方通過反射訪問該類的方法

  虛擬機可以對滿足以上3個條件的無用類進行回收,僅僅是“可以”,而且並不是像對象一樣,不使用了就必然會回收。是否對類進行回收,可以通過參數進行控制。

  參考資料:

  深入理解Java虛擬機

一步一步學JVM-垃圾回收