一 基礎知識
在分析之前,先上一張圖:
從上面可以看到,這個w3wp進程占用了376M內存,啟動了54個線程。
在使用windbg查看之前,看到的進程含有 *32 字樣,意思是在64位機器上已32位方式運行w3wp進程。這個可以通過查看IIS application Pool 的高級選項進行設置:
好了,接下打開Windbg看看這個w3wp進程占用了376M內存,啟動的54個線程。
1. 加載 WinDbg SOS 擴展命令
.load C:/Windows/Microsoft.NET/Framework/v2.0.50727/sos.dll
2. !dumpheap -stat
!DumpHeap 將遍歷 GC 堆對對象進行分析。
MT Count TotalSize Class Name78eb9834 1 12 System.ServiceModel.ServiceHostingEnvironment+HostingManager+ExtensionHelper
0118c800 101 14824 Free...63ce0004 19841 1111096 System.Reflection.RuntimeMethodInfo63ce2ee4 11080 2061036 System.Int32[]63ce0d48 34628 2242596 System.String63ce37b8 20012 3264884 System.Byte[]63cb4518 157645 4940676 System.Object[]Total 524310 objects
可以看到,w3wp上總共有524310個對象, 共占用了這些內存。
我們可以將上述上述列出的這些對象歸為2類:
1). 有根對象(在應用程序中對這些對象存在引用)
2). 自從上次垃圾回收之后新創建或無跟對象
要注意的是Free這項:
0118c800 101 14824 Free
這項一般都是GC not yet Compacted的空間或一些堆上分配的禁止GC compacted釘扣對象.
第一欄 : 類型的方法列表 MT(method type for the type)
第二欄:堆上的對象數量
第三欄:所有同類對象的總大小
3. !dumpheap -mt 63ce0d48
查看 63ce0d48單元的有哪些對象。
4. !do 103b3360
看看103b3360地址的string包含哪些內容
可見,103b3360地址的字符串value="System.Web.UI.PageRequestManager:AsyncPostBackError", 占120bytes. 這個字符串對象包含3個字段,它們的偏移量分別是4,8,12。
5. dd 103b3360
看看103b3360的值
從左往右第一列是地址,而第二列開始則是地址上的數據。
6. !dumpheap -type String -min 100
看看堆上所有大于100字節的字符串。 注意:假如 -min 85000(大于85000字節的字符串或對象將存儲在大對象堆上).
二. NET內存泄露分析案例
1 基礎認識
.net世界里,GC是負責垃圾回收的,但GC僅僅是回收哪些不可及的對象(無根對象),對于有應用的有根對象,GC對此無能為力。
.net一些內存泄漏的根本原因:
一些避免內存泄漏的建議:
對這些做基本了解后,我們將步入正題。
2. 案例分析
先上測試代碼:
1 public class LeakTest 2 { 3 PRivate static string leakString; 4 5 public LeakTest() 6 { 7 for (int i = 0; i < 1000; i++) 8 { 9 leakString += "LEAK";10 }11 }12 13 public string GetRamdonString()14 {15 System.Random random = new System.Random();16 17 string str = string.Empty;18 for (int i = 0; i < 25; i++)19 {20 str += str + random.Next(100);21 }22 return str;23 }24 25 public void NoDispose()26 {27 string str = GetRamdonString();28 29 ZipFile zip = new ZipFile();30 zip.AddEntry("a.txt", str);31 zip.AddEntry("b.txt", str);32 zip.Save("test.rar");33 //zip.Dispose();34 }35 }36 37 class Program38 {39 static void Main(string[] args)40 {41 LeakTest leakTest = new LeakTest();42 leakTest.NoDispose();43 Console.ReadLine();44 }45 }View Code
需要說明的是:
這里程序里面定義了一個Static 字符串,及使用了Ionic.Zip 這個Zip壓縮包,僅僅是為了模擬內存堆積現象,沒有調用zip.Dispose()方法,事實上Ionic.Zip并不會造成內存泄露。
正式開始了:
啊哈,好極了。 運行程序,好家伙,果然很耗費內存! 這么個小程序,吃了287M,并啟動了12個線程.
0:005> .load C:/Windows/Microsoft.NET/Framework64/v2.0.50727/sos.dll0:005> .load C:/Symbols/sosex_64/sosex.dll
0:005> !dumpheap -stat
1 0:012> !dumpheap -stat 2 PDB symbol for mscorwks.dll not loaded 3 total 12840 objects 4 Statistics: 5 MT Count TotalSize Class Name 6 000007ff001d2248 1 24 System.Collections.Generic.Dictionary`2+ValueCollection[[System.String, mscorlib],[Ionic.Zip.ZipEntry, Ionic.Zip.Reduced]] 7 000007ff000534f0 1 24 ZipTest.LeakTest 8 000007fee951e8e8 1 24 System.IO.TextReader+NullTextReader 9 000007fee94f8198 1 24 System.Security.Cryptography.RNGCryptoServiceProvider11 ...43 000007ff001d9130 1041 66624 Ionic.Zlib.DeflateManager+CompressFunc44 000007fee94d2d40 1023 73656 System.Threading.ExecutionContext45 000007fee951e038 3075 1387592 System.UInt32[]46 000007fee951ca10 3179 2450704 System.Int16[]47 0000000000207800 261 67034512 Free48 000007fee94d7d90 514 134251544 System.String49 000007fee94dfdd0 102 138593344 System.Byte[]50 Total 12840 objects
果然,我們看到了里面有2類大對象,分別占用了134M和138M . 好家伙!
0:005> !dumpheap -mt
1 0:012> !dumpheap -mt 000007fee94dfdd0 2 Address MT Size 3... 24 00000000026f11f0 000007fee94dfdd0 65560 25 0000000002701288 000007fee94dfdd0 65560 26 00000000027112a0 000007fee94dfdd0 65592 27 0000000002722b50 000007fee94dfdd0 65560 28 0000000002752b98 000007fee94dfdd0 65560 29 ... 47 000000000290ab98 000007fee94dfdd0 65560 48 000000000293abe0 000007fee94dfdd0 65560 49 ... 64 0000000002ac1378 000007fee94dfdd0 65560 65 0000000002ad1410 000007fee94dfdd0 65560 66... 103 00000000165a71e0 000007fee94dfdd0 67108888 104 0000000027c11000 000007fee94dfdd0 67108888 105 total 102 objects106 Statistics:107 MT Count TotalSize Class Name108 000007fee94dfdd0 102 138593344 System.Byte[]109 Total 102 objects
果然,有那么多65592和65560啊 啊
隨便找一個看一下:
0:005> !do 0000000002ba4790
1 0:012> !do 0000000002ba4790 2 Name: System.Byte[]3 MethodTable: 000007fee94dfdd04 EEClass: 000007fee90e26b05 Size: 65590(0x10036) bytes6 Array: Rank 1, Number of elements 65566, Type Byte7 Element Type: System.Byte8 Fields:9 None
哦。這是個一維的數組,有65566字節,推測應該好像是short(int16)長度。
繼續,
!gcroot 0000000002b42dd0
0:012> !gcroot 0000000002b42dd0 Note: Roots found on stacks may be false positives. Run "!help gcroot" formore info.Scan Thread 0 OSTHread 1d3cRSP:18ef58:Root:00000000025c5b88(Ionic.Zip.ZipFile)->00000000025d2578(Ionic.Zlib.ParallelDeflateOutputStream)->00000000025dc528(System.Collections.Generic.List`1[[Ionic.Zlib.WorkItem, Ionic.Zip.Reduced]])->000000000294ac38(System.Object[])->0000000002b32d78(Ionic.Zlib.WorkItem)->0000000002b42dd0(System.Byte[])...Scan Thread 10 OSTHread 3718
這里有點看頭了! 看其跟對象 Ionic.Zip.ZipFile 這個對象占著沒銷毀的內存呢!
RSP:18ef58:Root:00000000025c5b88(Ionic.Zip.ZipFile)->00000000025d2578(Ionic.Zlib.ParallelDeflateOutputStream)->00000000025dc528(System.Collections.Generic.List`1[[Ionic.Zlib.WorkItem, Ionic.Z
新聞熱點
疑難解答