天天看點

finalize方法

​ finalize()是Object中的方法,當垃圾回收器将要回收對象所占記憶體時,該方法被調用,即當一個對象被虛拟機宣告死亡時會先調用它的finalize()方法,讓此對象臨終前交代點遺言,當然對象也可以趁機複活。

死亡判定

引用計數器法

​ 給對象添加一個引用計數器,每當有一個地方引用它,計數器就加1,當引用失效時,計數器就減1,任何時刻當計數器為0的時候,這個對象就不能再被使用了。優點:實作簡單效率高。缺點:主流JVM不使用這個算法,因為無法解決對象循環引用的問題。

可達性分析算法

​ 通過一系列稱為 “GC Roots” 的對象作為起點,從這些節點開始向下搜尋,節點所走過的路徑稱為引用鍊,當一個對象到 GC Roots 沒有任何引用鍊相連的話,則證明此對象是不可用的。可作為GC root的對象有:方法區中常量引用的對象,方法區中靜态屬性引用的對象,虛拟機棧中引用的對象,本地方法中引用的對象。

可達性分析算法中,要宣告一個對象真正的死亡,要經曆兩次标記的過程:

  1. 如果對象在經曆可達性分析之後,發現沒有與GC root相連的引用鍊,将會被第一次标記并且進行第一次篩選,篩選的條件是是否有必要執行finalize()方法,當對象沒有finalize()方法或者虛拟機已經調用過finalize()方法,視為沒有必要執行。
  2. 如果這個對象被判定為有必要執行finalize()方法,那麼對象将會放置在一個F-Queue隊列中,稍後由一個虛拟機自動建立的、低優先級的Finalizer線程去執行它。finalize()方法是對象逃離死亡的最後一次機會,稍後GC将會對隊列進行第二次小規标記,如果對象要finalize()拯救它,隻需要與引用鍊上的任意一個對象建立關聯即可,那麼第二次标記的時候它将會被移出即将回收的集合,如果沒逃脫,就會真正被回收。

最後掙紮

​ 對象被判定死亡以後,還有機會掙紮一下。

​ 重寫finalize()方法,将對象重新引用到"GC Roots"鍊上

不确定性

finalize()隻會在對象記憶體回收前被調用一次,但是不保證裡面的方法會被執行完。如果執行比較慢,還沒來得及複活,就被殺死回收了。

finalize()的作用

其實,并沒有什麼亂用。

書中記載,“它不是C/C++中的析構函數,而是Java剛誕生時為了使C/C++程式員更容易接受它所做出的一個妥協”。

代碼實作

/**
 * @author Fibonacci
 * @date 2020-12-26 10:24
 */
public class QuoteType {

    @Override
    protected void finalize(){
        System.out.println("GC的時候會執行");
    }

    public static void main(String[] args) {
        // 建立一個對象
        QuoteType quoteType = new QuoteType();
        // 對象設定為null
        quoteType = null;
        // 啟用垃圾回收
        System.gc();

        // 阻塞等待垃圾回收完成
        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}