首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

finalize() 方法深度解析:為什麼不應依賴它釋放資源

     編輯:Java 程式設計入門

經典範例回顧

Thinking in Java 示範程式:在迴圈中大量建立 Chair 物件(不保留引用),觀察 finalize() 執行時機與數量。執行結果顯示:建立數萬個物件後,finalize() 才開始陸續執行,且執行數量遠少於建立數量;若手動呼叫 System.gc()、System.runFinalization() 或設定 runFinalizersOnExit(true),才會看到全部物件被終結。

核心機制分析

  1. 不可預測性:GC 執行時間由 JVM 決定(記憶體壓力、演算法、負載),finalize() 可能延遲秒級、分鐘級,甚至程式結束前永不執行。
  2. 非即時性:物件變「不可及」到 finalize() 執行間有任意間隙。範例中 created 計數器持續遞增,而 finalized 落後數萬。
  3. 單次執行保證:JVM 保證每個物件 finalize() 至多執行一次。若 finalize() 中重新建立強引用(復活),下次 GC 不會再呼叫 finalize()。
  4. 例外吞沒:finalize() 拋出未捕獲例外會被 JVM 忽略,導致後續終結動作中斷,極難除錯。
  5. 效能開銷:有 finalize() 的物件需額外進入 Finalizer 佇列、由專用執行緒處理,延長 GC 週期、增加記憶體壓力。

為什麼不適合關閉檔案/釋放鎖/斷開連線?

  • 資源釋放需確定性、及時性,finalize() 兩者皆無保證。
  • 若大量物件等待終結,資源耗盡(檔案描述符、資料庫連線)會發生在 GC 介入前。
  • 多執行緒環境下,Finalizer 執行緒可能成為瓶頸。

正確替代方案

  1. try-with-resources (Java 7+):AutoCloseable 介面,編譯器自動生成 finally 區塊呼叫 close(),確保及時釋放。
    try (FileInputStream fis = new FileInputStream("a.txt");
         BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
        // 使用資源
    } // 自動關閉,即使發生例外
  2. 顯式 close() / dispose():API 設計提供 close(),呼叫端負責在 finally 區塊調用。
  3. Cleaner / PhantomReference (Java 9+):比 finalize() 更可控的清理機制,但仍非即時,適用於原生記憶體釋放等非關鍵資源。

結論

finalize() 是「最後防線」,僅供記錄、統計等非關鍵清理。**切勿依賴它管理稀缺資源**。採用 try-with-resources 或顯式 close() 才是專業、可靠的資源管理之道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved