1. 程式人生 > >回收物件和方法區

回收物件和方法區

  • 回收物件,判斷物件是否是可回收的

引用計算演算法:給物件新增一個引用計數器,每當有一個地方引用它時,計數器的值就加1;當引用失效時就減1;任何時刻計數器為0的物件就是不可能再被使用的。但是大部分主流的Java虛擬機器裡面沒有選用引用計算演算法來管理記憶體,其中最主要的原因是它很難解決物件之間相互迴圈的問題。

可達性分析演算法:通過一系列的稱為“GC Roots”的物件作為起始點,從這些節點開始向下搜尋,搜尋所走的路徑稱為引用鏈,當一個物件到“GC Roots”沒有任何引用鏈相連時,則證明此物件是不可用的。

在Java語言中,可作為GC Roots的物件包括下面幾種:

1.虛擬機器棧(棧幀中的本地變量表)中引用的物件。

2.方法區中類靜態屬性引用的物件。

3.方法區中常量引用的物件。

4.本地方法棧中JNI(即一般說的Native方法)引用的物件。

 

無論是通過引用計數演算法判斷物件的引用數量,還是通過可達性分析演算法判斷物件的引用鏈是否可達,判斷物件是否存活都與“引用”有關。Java中引用分為4種:

  1. 強引用 在程式程式碼之中普遍存在的,類似“Object obj = new Object()”這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的物件。
  2. 軟引用 用來描述一些還有用但並非必須的物件。
  3. 弱引用 也用來描述一些還有用但並非必須的物件,強度比軟引用更弱一些。
  4. 虛引用 也稱為幽靈引用或幻影引用,它是最弱的一種引用關係。

 

即使在可達性分析演算法中不可達的物件,也並非是一定會被回收的,這時候它們暫時處於“準備”被回收的狀態,要真正回收一個物件,至少要經歷兩次標記過程:

  1. 如果物件在可達性分析後發現沒有與GC Roots相連線的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選的條件是此物件是否必要執行finalize()方法。當物件沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機器呼叫過,虛擬機器將這兩種情況都視為“沒有必要執行”。
  2. 如果這個物件被判定為有必要執行finalize()方法,那麼這個物件將會放置在F-Queue的佇列中,並在稍後有一個虛擬機器自動建立的、低優先順序的Finalizer執行緒去執行它。這裡的執行,是指虛擬機器會觸發這個方法,但並不承諾會等待它執行結束。finalize()方法是物件避免被回收的方法,如果在finalize()中重新與引用鏈上的任何一個物件建立關聯即可,這樣在第二次標記時它將被移出“即將回收”的集合。注意:任何一個物件的finalize()方法都只會被系統自動呼叫一次。

 

  • 回收方法區

永久代的垃圾收集的主要回收兩部分內容:廢棄常量和無用的類。(永久代是Hotspot虛擬機器特有的概念,是方法區的一種實現)

1.判斷一個常量是否是“廢棄常量”:沒有任何物件引用常量池中的常量。

2.判斷一個類是否是無用類:

1)該類所有的例項都已經被回收,也就是Java堆中不存在該類的任何例項。

2)載入該類的ClssLoader已經被回收。

3)該類對應的java.lang.Class物件沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

                                         

                                            摘抄自《深入理解Java虛擬機器:JVM高階特性與最佳實踐》(第二版) 周志明著