C#內存泄露與資源釋放 經驗總結

本文鏈接:http://blog.csdn.net/yokeqi/article/details/41083939


C#相比其他語言,擁有強大的垃圾回收機制,但並不是這樣,你就可以對內存管理放任不管,其實在稍不注意的時候,可能就造成了內存泄露,甚至因此程序崩潰。

以下是遇到過的內存優化-內存泄露的問題與應對方案。


場景:

1. Form.ShowDialog()問題。

private void button1_Click(object sender, EventArgs e)
{
    new Form2.ShowDialog();
}
如果你覺得寫這樣的一段代碼很Cool,很簡潔,你在項目也有這麼寫代碼,那你就碰到大麻煩了,你試試在Form2中開個大一點的數組來檢查內存,然後運行,按幾下button1按鈕,你就會發現,內存一直增加,即使你調用GC也無濟於事。


2. 窗體向全局性事件註冊了事件的問題。

public Form2()
{
    InitializeComponent();
    MyApp.FormChanged += FormChanged;
}
MyApp是一個靜態類,如果向這種類裏面註冊了事件,而又沒有取消註冊,這樣也會遇到大麻煩。即使在外部已經記得調用了Form2實例的Dispose也是沒用的。


實際上由於各個開發人員的水平跟接觸面不同,又沒有經過統一的培訓(各個人對內存釋放的理解與關注度不同,或者寫代碼時就沒考慮內存未被釋放這種問題),發現問題的時候項目往往已經做到了一個階段(SIT測試),系統也比較龐大了,這種時候才發現內存泄露的問題確實是很頭疼的。


解決方案:

1. 基於架構師的經驗,或者統一意見會議,在開發前對開發人員進行必要的統一培訓,對關係到性能、內存等會影響系統穩定性的解決方案進行培訓。這本身既有助於開發人員水平的提高,也對系統的穩定性方面提供很大的保障(項目可不是做完一個就沒了,這種培訓會帶來長久的增益效果)。

2. 注意託管資源與非託管資源的釋放區別,非託管資源是需要手動釋放的。

3. 使用using關鍵字,避免忘記Dispose的情況,如上面的ShowDialog問題。(using中還起到了try-catch的作用,避免由於異常未調用Dispose的情況)

4. 使用UnLoad事件或者析構函數,對註冊的全局事件進行取消註冊。

5. 特別注意自定義組件的穩定性更重要,發生問題時影響也更廣。注意繼承IDisposable接口,進行資源釋放,並且對有疑問/複雜邏輯的地方添加try-catch語句。(發現問題的人員不一定有權限修改這些組件)一定要保證組件健壯健壯,再健壯。這是我做組件的感悟~~~多麼痛的領悟!!


最後特別奉送一個"內存釋放"的大招:

調用這個API能讓你的內存一下爆減:貼一段網上的示例代碼

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
/// <summary>    
/// 釋放內存    
/// </summary>    
public static void ClearMemory()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
    {
        SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
    }
}
是不是很給力,一調用內存就降下來。先別高興太早,這其實是僞釋放,只爲暫時解決內存大量泄露導致系統崩潰而急需解決的情況。
具體原因:http://blog.sina.com.cn/s/blog_49f8960e0100081x.html,關鍵字:將物理內存轉到虛擬內存,涉及磁盤讀寫。

好處壞處都貼出來了,是否需要使用請君自己斟酌。

發佈了63 篇原創文章 · 獲贊 5 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章