.NET資源泄露與處理方案

.NET雖然擁有強大易用的垃圾回收機制,但並非由於這樣,你就能夠對資源管理聽任無論,其實在稍不注意的時候,可能就形成了資源泄露,甚至所以致使系統崩潰,到那時再來排查問題就已是困難重重。html

1、知識點簡單介紹數組

常見的資源泄露有:多線程

  • 內存泄漏:非託管資源沒有釋放、非靜態對象註冊了靜態實例。
  • GDI泄露:字體。
  • 句柄泄露:Socket或線程。
  • 用戶對象泄露:移除的對象未釋放。

2、具體實例函數

1. 內存泄漏學習

很常見的現象是分不清哪些對象須要釋放,對於控件、Stream等一些非託管資源也只管新增,卻沒有釋放,功能是實現了,卻埋了顆不小的雷。字體

private void button1_Click(object sender, EventArgs e)
{
    for(int i=0;i<1000;i++)
        this.Controls.Add(new TabPage());
}
private void button1_Click(object sender, EventArgs e)
{
    new Form2.ShowDialog();
}

若是你以爲寫這樣的代碼很Cool,很簡潔,你在項目中也有這麼寫代碼,那你就碰到大麻煩了,你試試在上面Form2中開個大一點的數組來檢查內存,而後運行,按幾下按鈕,你就會發現,內存一直增長,即便你調用了GC也無濟於事。因此,對於此類非託管資源要記住釋放,用完即廢能夠採用using關鍵字。this

public Form2()
{
    InitializeComponent();
    MyApp.FormChanged += FormChanged;
}

上面這個例子中,MyApp是一個靜態類,若是在實例對象中向這種類裏面註冊了事件,而又沒有取消註冊,這樣也會遇到大麻煩,即便在外部已經記得調用了Form2的Dispose也是沒用的。spa

解決方案.net

2. GDI泄露線程

通常會跟字體相關,例如我曾在Android上用Cocos2d作一個小遊戲時頻繁地切換字體、Dev控件的Font屬性賦值也會有這種現象。

XXX.Font = new Font(...)

解決方案

  • 這個問題我目前是採用字體池來解決,相似線程池的概念,相同Key值取同一個對象。如有更好方案歡迎留言討論

3. 句柄泄露

通常跟Socket和Thread(線程)有關

for(int i=0;i<1000;i++){
    new Thread(()=>{
        Thread.Sleep(1000);
    }).Start();
}

解決方案

  • Socket的場景暫時沒遇到。
  • 線程問題採用線程池相關的輔助類能有效解決,例如ThreadPool、Task、Parallel。

4. 用戶對象泄露

通常跟移除的對象未釋放有關

private void button1_Click(object sender, EventArgs e)
{
    tab.Remove(tabPage);
}

3、最後特別奉送一個內存釋放的大招

[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);
    }
}

調用以上API能讓你的內存一下爆減,是否是很給力,一調用內存就降下來了。But,先別高興太早,這實際上是僞釋放,只是暫時解決內存大量泄漏致使系統崩潰的應急處理方案。具體緣由參考:SetProcessWorkingSetSize函數的騙局,關鍵信息:物理內存轉虛擬內存,涉及磁盤讀寫。好處壞處都貼出來了,是否須要使用請君本身斟酌。

4、總結

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

  • 資源泄露的場景每每是相互關聯的,發生最多的就是內存泄漏,而除了寫法可能有問題外,也多是由於句柄泄露或用戶對象泄露引發的。

5、參考資料

相關文章
相關標籤/搜索