finalize()是Object中的方法,當垃圾回收器将要回收對象所占記憶體時,該方法被調用,即當一個對象被虛拟機宣告死亡時會先調用它的finalize()方法,讓此對象臨終前交代點遺言,當然對象也可以趁機複活。
死亡判定
引用計數器法
給對象添加一個引用計數器,每當有一個地方引用它,計數器就加1,當引用失效時,計數器就減1,任何時刻當計數器為0的時候,這個對象就不能再被使用了。優點:實作簡單效率高。缺點:主流JVM不使用這個算法,因為無法解決對象循環引用的問題。
可達性分析算法
通過一系列稱為 “GC Roots” 的對象作為起點,從這些節點開始向下搜尋,節點所走過的路徑稱為引用鍊,當一個對象到 GC Roots 沒有任何引用鍊相連的話,則證明此對象是不可用的。可作為GC root的對象有:方法區中常量引用的對象,方法區中靜态屬性引用的對象,虛拟機棧中引用的對象,本地方法中引用的對象。
可達性分析算法中,要宣告一個對象真正的死亡,要經曆兩次标記的過程:
- 如果對象在經曆可達性分析之後,發現沒有與GC root相連的引用鍊,将會被第一次标記并且進行第一次篩選,篩選的條件是是否有必要執行finalize()方法,當對象沒有finalize()方法或者虛拟機已經調用過finalize()方法,視為沒有必要執行。
- 如果這個對象被判定為有必要執行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();
}
}
}