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

.NET 托管記憶體洩漏分析與診斷實戰

     編輯:關於.NET

什麼是托管環境下的「洩漏」?

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

GC 回收機制速覽

  • 根物件集合:靜態變數、方法參數、區域變數、CPU 寄存器等。
  • 標記-清除演算法:從根開始遍歷所有可達物件並標記,未標記者視為垃圾回收。
  • 分代機制:Gen 0 (新生代)、Gen 1、Gen 2 (老年代),隨 Age 增長升代;大型物件 (>85,000 bytes) 直接進入 LOH (大型物件堆),不壓縮。
  • 兩個堆:SOH (小型物件堆,含 Gen 0/1/2) 與 LOH。

洩漏示意圖解

洩漏前堆狀態

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

GC 後堆狀態

若可達區域含有「邏輯上已死」但仍被參考的物件,且業務反覆執行創建新實例 → Gen 3 持續增長 → 服務終結。

結構化診斷步驟

  1. 監控記憶體趨勢:用 LoadRunner 腳本重現業務,觀察 Private Bytes / Managed Heap 持續上升不降的場景。
  2. 重啟應用:清空無關物件,建立乾淨基線。
  3. 執行一次問題業務 → Full GC 後 Dump/Snapshot (工具如 .NET Memory Profiler、WinDbg + SOS)。
  4. 再次執行同業務 → 再次 Full GC 後 Dump/Snapshot。
  5. 比對兩次快照:找出「新增」的物件類型/實例 (第二次相對第一次新增者),即為洩漏候選者。
  6. 優先檢查順序:
      li>應用程式命名空間下的類型
    • Framework 類型中已呼叫 Dispose() 仍存活的物件
    • 靜態變數、事件訂閱、快取等常見持有者
  7. 分析 Root Path:確認洩漏物件被誰參考,修改代碼切斷不應有的參考鏈。

實戰案例:ASP.NET 應用記憶體洩漏排查

現象

查詢業務執行數次後,w3wp 進程記憶體每次增長數 MB 至數十 MB,PerfMon 顯示 GC 執行但 Managed Heap 像增不減,最終導致服務宕機。

使用 .NET Memory Profiler 定位

Profiler 比較視圖

工具提供:Types 清單、Type details、Instance details、Call stacks、Native memory、Field Sets (Standard/Dispose Info/Heap Utilization) 等視圖。

第一發現:靜態 XmlDataSource 導致 XmlDataSourceView 洩漏

頁面含 static XmlDataSource 欄位,生命週期跟隨 AppDomain,不被 GC。每次查詢產生新的 XmlDataSourceView 並訂閱其事件,導致 View 無法釋放。

XmlDataSource 實例

引用鏈

修復:將欄位改為非靜態,每次請求建立新實例,請求結束隨即可回收。單次業務節省 ~11 MB。

第二發現:SiteMap 事件導致 Page 物件洩漏

開啟 Dispose Info 過濾器,發現頁面及 Master Page 皆已 Dispose 但未被 GC,Root Path 指向 SiteMap 的靜態事件 SiteMapResolve。

Dispose Info

SiteMap 引用

原因:頁面訂閱 SiteMapResolve 事件,委派持有 Page 實例 (this),而 SiteMap 為全域靜態物件 → Page 無法回收,連帶大量控制項狀態資料駐留記憶體 (每頁 ~46 MB)。

對策:取消事件訂閱、改用靜態處理函式、或避免在 Page 中訂閱全域靜態事件。

總結

托管洩漏本質是「非預期的強參考」。善用分代 GC 知識、Profiling 工具、兩次快照比對法、Root Path 分析,配合業務邏輯理解,即可精準定位並修復。修復往往簡單 (移除靜態、取消訂閱、實作 IDisposable 正確),難點在診斷。

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