Java 無解構函式,改以 finalize() 配合垃圾回收器(GC)釋放資源。但兩者行為差異極大,錯誤依賴 finalize() 會導致資源洩漏。
核心差異
| 特性 | C++ 解構函式 | Java finalize() |
| 呼叫時機 | 物件離開作用域(堆疊)或 delete(堆積)時確定呼叫 | GC 回收物件前呼叫,時機非確定性 |
| 保證執行 | 是(除非程式異常終止) | 否:程式結束前 GC 若未執行則不會呼叫 |
| 記憶體模型 | 堆疊/堆積雙重支援 | 所有物件在堆積 |
| 基類鏈結 | 自動由衍生至基底遞迴呼叫 | 不自動呼叫,需手動 super.finalize() |
垃圾回收器行為
- GC 以低優先權背景執行緒運行,僅在記憶體壓力大時回收。
System.gc() 僅是建議,非命令,不保證立即回收。
- Java 1.1 引入
System.runFinalizersOnExit(true) 強制程式結束時呼叫所有 finalize(),但會造成明顯延遲,且已棄用(不安全)。
實測範例
建立 1000 個 thing 物件,未呼叫 System.gc() 時,程式結束零物件被終結;啟用 System.gc() 後約 963 個被終結,證明 GC 行為不可預測。
最佳實務
- 勿依賴 finalize() 釋放關鍵資源(檔案、Socket、資料庫連線、鎖)。
- 採用 try-finally 或 try-with-resources (Java 7+) 明確釋放:
FileInputStream fis = new FileInputStream("data.txt");
try {
// 使用 fis
} finally {
fis.close(); // 確定執行
}
- 若必須實作
finalize(),僅作為安全網補釋非記憶體資源,並呼叫 super.finalize()。
結論
Java 以 GC 換取開發便利,犧牲了確定性資源釋放。開發者必須主動管理資源生命週期,finalize() 僅是最後防線,非主要機制。
- 上一篇文章: C/C++ 中 lvalue 與 rvalue 的正確釋義
- 下一篇文章: C++ 管理擴展:無縫整合 .NET 與原生代碼
Copyright ©
程式碼之家 All Rights Reserved