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

.NET 記憶體管理深度解析:GC、Dispose、Close、Finalize 與非託管資源釋放模式

     編輯:關於.NET

.NET 物件生命週期包含建立、使用、釋放三階段。理解記憶體管理機制,特別是非託管資源的正確釋放,是編寫高效能、無記憶體洩漏應用程式的關鍵。

物件建立與記憶體配置

宣告變數(FileStream fs)僅在堆疊配置參考位址。new FileStream(...) 觸發三步驟:

  1. 託管堆配置記憶體(含所有實例欄位 + 物件標頭)
  2. 欄位初始化(值型別歸零、參考型別為 null、string 為空字串)
  3. 呼叫建構函式,初始化非託管資源(如檔案控制代碼)

垃圾收集器 (GC) 機制

GC 自動回收不再被參考的物件,觸發時機:

  • 第 0 代物件填滿(記憶體壓力)
  • 呼叫 GC.Collect()(不建議頻繁使用,會暫停執行緒)
  • AppDomain 卸載
  • CLR 關閉

GC 回收前會檢查物件是否有 Finalize 方法(C# 寫作 ~ClassName()),有則先呼叫以釋放非託管資源。

非託管資源釋放問題

FileStream 內部持有 SafeFileHandle 封裝 Win32 HANDLE。若未呼叫 Close(),檔案會被鎖定無法刪除,直到 GC 執行 Finalize 才會釋放。

錯誤示範

FileStream fs = new FileStream(@"C:\test.txt", FileMode.OpenOrCreate);
Console.ReadLine(); // 此時嘗試刪除檔案會失敗
// 程式結束時 GC 才會釋放

正確做法:明確呼叫 Close/Dispose

FileStream fs = new FileStream(@"C:\test.txt", FileMode.OpenOrCreate);
// 使用檔案...
fs.Close(); // 立即釋放非託管資源
File.Delete(@"C:\test.txt"); // 成功

Dispose 模式完整實作

封裝非託管資源的類別應實作標準模式:

public class MyResourceWrapper : IDisposable {
    private SafeHandle _handle; // 非託管資源
    private bool _disposed = false;

    // 公開給呼叫端明確釋放
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this); // 告訴 GC 不需再呼叫 Finalize
    }

    // 核心釋放邏輯
    protected virtual void Dispose(bool disposing) {
        if (!_disposed) {
            if (disposing) {
                // 釋放託管資源
            }
            // 釋放非託管資源
            _handle?.Dispose();
            _disposed = true;
        }
    }

    // Finalize 保底機制
    ~MyResourceWrapper() {
        Dispose(false);
    }
}

關鍵差異總結

方法呼叫者用途
Finalize (~Ctor)GC 自動呼叫保底釋放非託管資源
Dispose()開發者手動呼叫及時釋放託管+非託管資源
Close()開發者手動呼叫通常等同 Dispose,語意更明確

最佳實務原則

  1. 使用 using 區塊確保 Dispose 被呼叫
  2. 實作 IDisposable 時務必提供 Finalize 保底
  3. 釋放後不可再使用物件(已損毀狀態)
  4. 託管堆記憶體永遠由 GC 掌控,無法手動釋放

掌握 Dispose 模式,讓非託管資源「有借有還」,是 .NET 專業開發者的必修課。

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