.Net 內存泄露無外乎那幾類:
引用未消除,事件未刪除
如果是WPF應用程序,常見的有Image 對象釋放問題,綁定到非依賴屬性或未實現INotifyPropertyChanged 接口的對象屬性.這里不細述.
本文介紹如何使用強大的.Net Memory Profiler 分析.Net 應用程序內存泄露. 使用的Demo 是 使用Mdbg.exe 調試.net 程序 中的Demo.
Sample Code:
namespace MemLeakProfileDemo
{
public partial class Form1 : Form
{
private Fool fool;
private FoolBrother brother;
public Form1()
{
InitializeComponent();
fool = new Fool();
brother = new FoolBrother();
//引用fool
brother.YoungFool = fool;
}
private void btnAlloc_Click(object sender, EventArgs e)
{
var i = 10;
//AllocalHugeMem 會申請10M的內存
fool.AllocalHugeMem();
}
private void btnWrongRelease_Click(object sender, EventArgs e)
{
//雖然fool 指向null,但 brother保留了對fool的引用,GC無效果.內存泄露
fool = null;
GCRelease();
}
private void btnRightRelease_Click(object sender, EventArgs e)
{
//消除 brother 對fool的引用,GC效果明顯
fool = null;
brother = null;
GCRelease();
}
private void GCRelease()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
public class Fool
{
private IList<byte[]> list = new List<byte[]>();
public void AllocalHugeMem()
{
var buffer = new byte[10 * 1024 * 1024];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 1;
}
list.Add(buffer);
}
}
public class FoolBrother
{
public Fool YoungFool
{
get;
set;
}
}
}
- 使用.Net Memory Profiler 啟動 Demo.exe,

- 先抓個快照(Collect Snapshot)
- 多點擊幾次 Allocal Mem 按鈕,申請內存,再點擊 Wrong Release Mem 按鈕.再抓個快照.
此時:
//雖然fool 指向null,但 brother保留了對fool的引用,GC無效果.內存泄露
fool = null;
GCRelease();
由於有個 FoolBrother 對象強引用了fool對象,fool對象無法被GC掉. 通過強大的工具,我們可以直觀的看到:

有一個Fool 對象instance 未被釋放.雙擊該行查看:

可以看到該對象引用的計數是1,GC 的Age,右邊是創建該對象的堆棧.
雙擊Instances 行.出現清晰的引用關系圖:

一切盡在眼前!
反之,可以點擊 Right Release Mem 按鈕,將FoolBrother 對象清除,再抓快照,對比效果.
回頭有時間再用此Demo 介紹如何使用Windbg SOS擴展找出內存泄露.
