需解構的物件:
結果:物件在記憶體多存活至少一輪 GC(通常 9+ 輪 Gen 0 收集),甚至晋升到 Gen 2 長期駐留。
有解構函數的物件會延遲代際晋升,增加 GC 壓力。
public class ResourceHolder : IDisposable
{
private IntPtr _handle; // 非受控資源
private bool _disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 關鍵:告訴 GC 不需呼叫 Finalize
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// 釋放受控資源
}
// 釋放非受控資源
ReleaseHandle(_handle);
_handle = IntPtr.Zero;
_disposed = true;
}
~ResourceHolder() => Dispose(false); // 保底:使用者忘記 Dispose
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hObject);
private void ReleaseHandle(IntPtr h) => CloseHandle(h);
}
using (var resource = new ResourceHolder())
{
resource.DoWork();
} // 編譯器產生 try/finally 呼叫 Dispose()
| 特性 | 解構函數 | IDisposable + using |
|---|---|---|
| 時機 | 非確定性(GC 決定) | 確定性(程式碼控制) |
| 效能 | 差(延遲回收、額外執行緒) | 優(立即釋放) |
| 適用資源 | 非受控資源保底 | 所有資源(受控+非受控) |
| 例外安全 | 無保證 | using 保證 finally 執行 |
IDisposable 管理所有資源Dispose(false))using 或 try/finally 確保 Dispose()GC.SuppressFinalize(this) 移除終結佇列登記Dispose 中存取其他終結物件(可能已被終結)