在傳統 Native 開發中,洩漏指忘記釋放記憶體;但在 .NET 托管環境中,GC (垃圾收集器) 負責管理托管堆。此處的「洩漏」意指:物件本應被回收,卻因與 Root 物件集合保持不應存在的參考關係,導致 GC 誤判為「仍在使用」而無法釋放。隨著程式反覆執行,這類物件累積於堆中 (特別是 Gen 3),最終導致記憶體耗盡、服務崩潰。

正常 GC 後,不可達物件被釋放:

若可達區域含有「邏輯上已死」但仍被參考的物件,且業務反覆執行創建新實例 → Gen 3 持續增長 → 服務終結。
Dispose() 仍存活的物件查詢業務執行數次後,w3wp 進程記憶體每次增長數 MB 至數十 MB,PerfMon 顯示 GC 執行但 Managed Heap 像增不減,最終導致服務宕機。

工具提供:Types 清單、Type details、Instance details、Call stacks、Native memory、Field Sets (Standard/Dispose Info/Heap Utilization) 等視圖。
頁面含 static XmlDataSource 欄位,生命週期跟隨 AppDomain,不被 GC。每次查詢產生新的 XmlDataSourceView 並訂閱其事件,導致 View 無法釋放。


修復:將欄位改為非靜態,每次請求建立新實例,請求結束隨即可回收。單次業務節省 ~11 MB。
開啟 Dispose Info 過濾器,發現頁面及 Master Page 皆已 Dispose 但未被 GC,Root Path 指向 SiteMap 的靜態事件 SiteMapResolve。


原因:頁面訂閱 SiteMapResolve 事件,委派持有 Page 實例 (this),而 SiteMap 為全域靜態物件 → Page 無法回收,連帶大量控制項狀態資料駐留記憶體 (每頁 ~46 MB)。
對策:取消事件訂閱、改用靜態處理函式、或避免在 Page 中訂閱全域靜態事件。
托管洩漏本質是「非預期的強參考」。善用分代 GC 知識、Profiling 工具、兩次快照比對法、Root Path 分析,配合業務邏輯理解,即可精準定位並修復。修復往往簡單 (移除靜態、取消訂閱、實作 IDisposable 正確),難點在診斷。