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

效能瓶頸深度剖析:調試 OutOfMemoryException 實戰紀實

     編輯:關於.NET

前文介紹效能測試基礎流程,並以 2MB 文本對比冒泡/快速排序。為探究極限,嘗試 700MB 大文件測試(原擬 2GB,但 32 位進程地址空間上限 2GB,扣除核心 2GB,用戶態僅 2GB;除非啟用 /LARGEADDRESSAWARE 讓用戶態擴至 3GB)。

測試資料製造


dir /s /b c:\windows > d:\test.txt
FOR /L %i IN (1,1,100) DO type test.txt >> testdata.txt

生成數百 MB 測試文件。

異常捕獲與 SOS 載入

運行排序程序,拋出 OutOfMemoryException。附加調試器,載入 SOS:


.loadby sos clr
!pe

異常堆疊揭示:StreamReader.ReadToEnd() → StringBuilder.ToString() 觸發 OOM。

!ao (AnalyzeOOM) 定位記憶體區域


!ao
Managed OOM occured after GC #312 (Requested to allocate 1649667816 bytes)
Reason: Didn't have enough memory to allocate an LOH segment
Detail: LOH: Failed to reserve memory (1652555776 bytes)

元兇:大物件堆 (LOH) 無法分配 ~1.5GB 連續空間。

!eeheap -gc 觀察堆分佈


Large object heap starts at 0x02911000
segment begin allocated size
02910000 02911000 02913240 0x2240(8768)
Total Size: 0x629424c0 (1653875904 bytes)

!dumpheap 統計 LOH 物件分佈


!dumpheap -stat 02911000 02911000+02913240
MT Count TotalSize Class Name
571afb78 1119 31332 System.Text.StringBuilder
571b1d88 1120 17933440 System.Char[]

Char[] 佔據 171MB,StringBuilder 實例 1119 個。

!gcroot 追蹤根引用鏈


!gcroot 03fd1000 (某 Char[] 實例)
Root: 0191d2e0(StringBuilder) -> ... -> 03fd1000(Char[])

追溯至 0191d2e0 (StringBuilder),再 !gcroot 發現其被多個堆疊幀引用:


ESP:17ed58:Root: 0191d2e0(StringBuilder)

!dumpstack 還原調用堆疊


0017ed30 5713e61e System.Text.StringBuilder.ToString()
0017ed5c 57121991 System.IO.StreamReader.ReadToEnd()
0017ed70 002f0136 Program.Main()

鐵證: StreamReader.ReadToEnd() 內部使用 StringBuilder 累積整個 700MB 文件內容,最終 ToString() 嘗試分配 1.5GB 連續字串,擊穿 LOH。

根因總結與優化方向

  1. 一次性讀入巨大文件 是災難根源。ReadToEnd() 適用於小/中型文件。
  2. 分塊流式處理: 使用 StreamReader.ReadBlock 或 ReadLine 逐塊處理,避免全量駐留記憶體。
  3. 外部排序: 超大數據排序應採用歸併排序 + 臨時文件,而非全量記憶體排序。
  4. 64 位進程: 編譯目標 x64 或 Any CPU (Prefer 32-bit = false),打破 2GB/3GB 限制。

調試工具箱速查

命令用途
!pe顯示當前異常詳細資訊
!ao分析 OOM 發生的堆區域與請求大小
!eeheap -gc列出各代堆與 LOH 起始/結束地址
!dumpheap -stat [start] [end]統計指定範圍內物件類型/數量/大小
!dumpheap -mt <MethodTable> [range]列出特定類型實例地址
!gcroot <addr>追蹤物件被誰引用(GC 根鏈)
!dumpstack顯示非託管+託管混合調用堆疊

掌握 SOS 核心命令,讓記憶體疑難雜症無所遁形。

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