原文地址:http://blogs.msdn.com/b/tess/archive/2008/02/15/net-debugging-demos-lab-3-memory.aspx
操作步驟:
1、產生壓力:tinyget -srv:localhost -uri:/BuggyBits/Links.aspx -loop:4000
2、觀察taskmgr的輸出,w3wp的記憶體每秒鐘大概增長100M。
3、記憶體到700M左右的時候,抓一個hang dump
4、由於這是一個memory的問題,所以我們要先看GC Heap的情況,運行命令:!eeheap -gc,結果如下:
GC Heap Size 0x2b307720(724596512)
由於dump一共870M,而GC佔用了720M左右,所以我們的重點在於託管記憶體的分析。
5、看heap的整體狀況,運行!dumpheap -stat,結果如下:
790fd8c4 49787 721599752 System.String
嗯,720M的託管記憶體中,String佔用了絕大多數。
6、看一下string的情況,根據2/8原則,大小相同的string也許會很多,這裡我們過濾一下,看看10K以上大小的字串,運行命令:!dumpheap -mt 790fd8c4 -min 10000
0331d6dc 790fd8c4 20020
03322534 790fd8c4 20020
0332738c 790fd8c4 20020
0332c1e4 790fd8c4 20020
0333103c 790fd8c4 20020
大部分都是20K的字串,隨便找一個,我們需要看它被誰分配的
7、運行!gcroot 0331d6dc,結果如下:
Scan Thread 16 OSTHread 318
Scan Thread 18 OSTHread c38
Scan Thread 19 OSTHread a40
Scan Thread 20 OSTHread c00
Scan Thread 24 OSTHread 998
Scan Thread 14 OSTHread 4cc
Finalizer queue:Root:0331d6b8(Link)->
0331d6c8(System.Text.StringBuilder)->
0331d6dc(System.String)
在14號線程中,Link引用了這個字串。而且我們看到,link是在Finalizer Queue中的。
8、查看finalizequeue,輸出如下:
057e0bcc 35998 575968 Link
一共35998個Link對象。由於該對象存在於Finalizequeue中,所以一定顯示的實現了Finalize方法。
9、查看該方法,代碼如下:
~Link()
{
//some long running operation when cleaning up the data
Thread.Sleep(5000);
}
10、換個方向,看上面步驟7中的那個Link對象,!do 0331d6b8,輸出結果如下:
MT Field Offset Type VT Attr Value Name
790fdc5c 4000006 4 ...ext.StringBuilder 0 instance 0331d6c8 url
790fd8c4 4000007 8 System.String 0 instance 029bb0b8 name
再看第一個url對象,運行!do 0331d6c8 ,結果如下:
MT Field Offset Type VT Attr Value Name
791016bc 40000b1 8 System.IntPtr 1 instance dc1d8 m_currentThread
79102290 40000b2 c System.Int32 1 instance 2147483647 m_MaxCapacity
790fd8c4 40000b3 4 System.String 0 instance 0331d6dc m_StringValue
注意最後一行的那個m_StringValue,對比一下步驟7中的!gcroot輸入。
從這裡我們看到,Link中包含了一個StringBuilder,而StringBuilder中包含了一個20K的字串。
11、看代碼:
public Link(string name, string url)
{
this.name = name;
this.url.Append(url);
}
可以看到,Link對象的構造方法中,引用了字串。
12、再回頭看上面的步驟9,Link自作聰明的實現了Finalize方法,但是該方法執行的時間太長(這裡是5秒鐘),導致記憶體回收的時候,遲遲不能把該對象回收掉。因為Link引用了字串url,所以相應的字串也無法被回收。這樣記憶體就上漲的很快了。
Over