被呼叫的前提是必須重寫此方法, 同時未被呼叫過, 因為此方法只會呼叫一次
), 常用於處理資源釋放 如關閉檔案, 通訊端, 資料庫連線等
- 如果物件A與 GC Roots失去聯絡, 則進行第一次標記
- 是否執行 finalize()方法的判斷過程:
(1) 物件A重寫了 finalize()方法(如沒有重寫意味著沒有復活的過程), 同時 finalize()方法已呼叫過一次, 則判定物件A為不可觸及的狀態
(2) 物件A重寫了 finalize()方法, 且還未執行過, 那麼物件A會被插入到一種 F-Queue佇列(參照佇列)中, 由一個虛擬機器器自動建立的, 低優先順序的 finalizer執行緒觸發其 finalize()方法執行
(3) - 稍後(finalizer執行緒的觸發後), 將會對 F-Queue佇列中的物件進行第二次標記. 此時如果物件A在 finalize()中復活了(也就是重新建立了, 與 GC Roots的聯絡), 那麼在此次標記時, 物件A會從’即將回收’的集合中移出. 之後, 如果物件A再次出現與 GC Roots失去聯絡的情況, 會直接成為不可觸及的狀態, 因為 finalize()方法只會被呼叫一次
public class FinalizeTestApp {
/** GC Roots*/
public static FinalizeTestApp objA;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("invoking `finalize` by GC");
/** 賦予參照地址, 目的為復活*/
objA = this;
}
public static void main(String[] args) {
try {
objA = new FinalizeTestApp();
/** 刪除參照地址*/
objA = null;
/** System.gc()或 Runtime.getRuntime().gc(); 會顯式的觸發 Full GC
* 即使直接呼叫 以上方法, 也無法保證對垃圾收集器的呼叫
* */
System.gc();
System.out.println("GC 1");
/** 由於 Finalizer執行緒優先順序較低, 暫停2秒, 為了保證 GC的執行*/
Thread.sleep(2000);
if (objA == null) {
System.out.println("obj is dead");
} else {
System.out.println("obj is still alive");
}
/** 重複了上面程式碼, 為了演示 finalize()的被呼叫次數*/
objA = null;
System.gc();
System.out.println("GC 2");
/** 由於 Finalizer執行緒優先順序較低, 暫停2秒, 為了保證 GC的執行*/
Thread.sleep(2000);
if (objA == null) {
System.out.println("obj is dead");
} else {
System.out.println("obj is still alive");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
輸出:
> GC 1
> invoking `finalize` by GC
> obj is still alive
> GC 2
> obj is dead
- 當執行緒執行到安全區域的程式碼片段時, 首先會標識已經進入了安全區域, 如果這段時間內發生 GC, JVM會忽略標識為安全區域的執行緒
- 當執行緒即將離開安全區域時, JVM會檢查是否已經完成 GC, 如果完成了, 則繼續執行, 否則執行緒必須等待直到收到可以安全離開安全區域的訊號為止
如果您覺得有幫助,歡迎點贊哦 ~ 謝謝!!