.NET資源泄露與處理方案知識點分享

 更新時間:2020-01-15 16:00:32   作者:佚名   我要評論(0)

.NET雖然擁有強大易用的垃圾回收機制,但并不是因為這樣,你就可以對資源管理放任不管,其實在稍不注意的時候,可能就造成了資源泄露,甚至因此導致系統崩潰,到那時

.NET雖然擁有強大易用的垃圾回收機制,但并不是因為這樣,你就可以對資源管理放任不管,其實在稍不注意的時候,可能就造成了資源泄露,甚至因此導致系統崩潰,到那時再來排查問題就已經是困難重重。

一、知識點簡單介紹

常見的資源泄露有:

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

二、具體實例

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關鍵字。

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

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

解決方案

  • 注意托管資源和非托管資源的釋放區別,非托管資源是需要手動釋放的。
  • 使用using關鍵字,避免忘記Dispose的情況,如上面的ShowDialog問題。(using中還起到了try-catch的作用,避免由于異常未調用Dispose的情況)
  • 使用UnLoad事件或者析構函數,對注冊的全局事件進行取消注冊。
  • 特別注意自定義組件的穩定性更重要,發生問題時影響也更廣。注意繼承IDisposable接口,進行資源釋放

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

三、最后特別奉送一個內存釋放的大招

[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函數的騙局,關鍵信息:物理內存轉虛擬內存,涉及磁盤讀寫。好處壞處都貼出來了,是否需要使用請君自己斟酌。

四、總結

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

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

參考文章:

C#中event內存泄漏總結

C# 字體池技術實現

以上就是本次介紹的全部相關知識點,感謝大家的學習和對腳本之家的支持。

相關文章

  • .NET資源泄露與處理方案知識點分享

    .NET資源泄露與處理方案知識點分享

    .NET雖然擁有強大易用的垃圾回收機制,但并不是因為這樣,你就可以對資源管理放任不管,其實在稍不注意的時候,可能就造成了資源泄露,甚至因此導致系統崩潰,到那時
    2020-01-15
  • asp.net大文件上傳解決方案實例代碼

    asp.net大文件上傳解決方案實例代碼

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 構建前端頁面,用 Axios 從前端訪問后端 API ,包括文件的上傳和下載。 準備文件上傳的API #region 文件上傳 可以帶參
    2020-01-15
  • .Net Core讀取Json配置文件的實現示例

    .Net Core讀取Json配置文件的實現示例

    前言:在與傳統的asp.net MVC項目相比,.net core項目在項目目錄的文件結構上和功能上與前者都有很大的區別。例如:在.net core中使用Startup.cs取代Global.asax文件
    2020-01-15
  • .net core部署到windows服務上的完整步驟

    .net core部署到windows服務上的完整步驟

    前言 Net core 項目部門在Windows有很多種方式,大致有以下幾種, dotnet 命令, iis(windowshosts), 一些開源的應用容器(docker ) 基于一些exe 程
    2020-01-15
  • .NET Core 微信小程序退款步驟——(統一退款)

    .NET Core 微信小程序退款步驟——(統一退款)

    繼上一篇".NET Core 微信小程序支付——(統一下單)后",本文將實現統一退款功能,能支付就應該能退款嘛,一般涉及到錢的東西都會比較敏感,所以在設計退款流程時一
    2020-01-15
  • .NET core 3.0如何使用Jwt保護api詳解

    .NET core 3.0如何使用Jwt保護api詳解

    摘要: 本文演示如何向有效用戶提供jwt,以及如何在webapi中使用該token通過JwtBearerMiddleware中間件對用戶進行身份認證。 認證和授權區別? 首先我們要弄清楚認證
    2020-01-15
  • .Net Core下HTTP請求IHttpClientFactory示例詳解

    .Net Core下HTTP請求IHttpClientFactory示例詳解

    使用方式 IHttpClientFactory有四種模式: 基本用法 命名客戶端 類型化客戶端 生成的客戶端 基本用法 在 Startup.ConfigureServices 方法中,通過在
    2020-01-15
  • .net core webapi通過中間件獲取請求和響應內容的方法

    .net core webapi通過中間件獲取請求和響應內容的方法

    本文主要根據中間件來實現對.net core webapi中產生的請求和響應數據進行獲取并存入日志文件中; 這里不詳細介紹日志文件的使用。你可以自己接入NLog,log4net,Exce
    2020-01-15
  • VS2019以及MFC的安裝詳細教程

    VS2019以及MFC的安裝詳細教程

    本文為大家分享了VS2019以及MFC的安裝詳細教程,供大家參考,具體內容如下 一、安裝過程: 1、搜索visual studio 進入官網。 2、選擇community 2019下載。 3、現在
    2020-01-15
  • asp.net core razor自定義taghelper的方法

    asp.net core razor自定義taghelper的方法

    又一個新的名詞(taghelper),通過taghelper是可以操作html標簽、條件輸出、更是自由添加內外元素。當然也內置了挺多的asp-開頭的taghelper。 下面文章中也簡單的帶大
    2020-01-15

最新評論

买宝宝用品赚钱吗 职业11选5高手买法 我要排列五的走势图 三分彩票网址 陕西11选五中奖规则表 幸运快三官网彩票 北京期货股票配资公司 湖北11选5走势图电视走势 江西多乐彩出号走势图 彩票官网注册 秒速赛车正版网址 快乐双彩玩法规则 青海福彩快三走势图 今天晚上黑龙江福彩p62开奖结果 pk10直播开奖赛车链接 11运夺金玩法说明 赛车总动员