.NET資源泄露與處理方案知識(shí)點(diǎn)分享
.NET雖然擁有強(qiáng)大易用的垃圾回收機(jī)制,但并不是因?yàn)檫@樣,你就可以對(duì)資源管理放任不管,其實(shí)在稍不注意的時(shí)候,可能就造成了資源泄露,甚至因此導(dǎo)致系統(tǒng)崩潰,到那時(shí)再來(lái)排查問(wèn)題就已經(jīng)是困難重重。
一、知識(shí)點(diǎn)簡(jiǎn)單介紹
常見(jiàn)的資源泄露有:
- 內(nèi)存泄漏:非托管資源沒(méi)有釋放、非靜態(tài)對(duì)象注冊(cè)了靜態(tài)實(shí)例。
- GDI泄露:字體。
- 句柄泄露:Socket或線程。
- 用戶對(duì)象泄露:移除的對(duì)象未釋放。
二、具體實(shí)例
1. 內(nèi)存泄漏
很常見(jiàn)的現(xiàn)象是分不清哪些對(duì)象需要釋放,對(duì)于控件、Stream等一些非托管資源也只管新增,卻沒(méi)有釋放,功能是實(shí)現(xiàn)了,卻埋了顆不小的雷。
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();
}
如果你覺(jué)得寫這樣的代碼很Cool,很簡(jiǎn)潔,你在項(xiàng)目中也有這么寫代碼,那你就碰到大麻煩了,你試試在上面Form2中開個(gè)大一點(diǎn)的數(shù)組來(lái)檢查內(nèi)存,然后運(yùn)行,按幾下按鈕,你就會(huì)發(fā)現(xiàn),內(nèi)存一直增加,即使你調(diào)用了GC也無(wú)濟(jì)于事。所以,對(duì)于此類非托管資源要記住釋放,用完即廢可以采用using關(guān)鍵字。
public Form2()
{
InitializeComponent();
MyApp.FormChanged += FormChanged;
}
上面這個(gè)例子中,MyApp是一個(gè)靜態(tài)類,如果在實(shí)例對(duì)象中向這種類里面注冊(cè)了事件,而又沒(méi)有取消注冊(cè),這樣也會(huì)遇到大麻煩,即使在外部已經(jīng)記得調(diào)用了Form2的Dispose也是沒(méi)用的。
解決方案
- 注意托管資源和非托管資源的釋放區(qū)別,非托管資源是需要手動(dòng)釋放的。
- 使用using關(guān)鍵字,避免忘記Dispose的情況,如上面的ShowDialog問(wèn)題。(using中還起到了try-catch的作用,避免由于異常未調(diào)用Dispose的情況)
- 使用UnLoad事件或者析構(gòu)函數(shù),對(duì)注冊(cè)的全局事件進(jìn)行取消注冊(cè)。
- 特別注意自定義組件的穩(wěn)定性更重要,發(fā)生問(wèn)題時(shí)影響也更廣。注意繼承IDisposable接口,進(jìn)行資源釋放
2. GDI泄露
一般會(huì)跟字體相關(guān),例如我曾在Android上用Cocos2d做一個(gè)小游戲時(shí)頻繁地切換字體、Dev控件的Font屬性賦值也會(huì)有這種現(xiàn)象。
XXX.Font = new Font(...)
解決方案
這個(gè)問(wèn)題我目前是采用字體池來(lái)解決,類似線程池的概念,相同Key值取同一個(gè)對(duì)象。若有更好方案歡迎留言討論
3. 句柄泄露
一般跟Socket和Thread(線程)有關(guān)
for(int i=0;i<1000;i++){
new Thread(()=>{
Thread.Sleep(1000);
}).Start();
}
解決方案
- Socket的場(chǎng)景暫時(shí)沒(méi)遇到。
- 線程問(wèn)題采用線程池相關(guān)的輔助類能有效解決,例如ThreadPool、Task、Parallel。
4. 用戶對(duì)象泄露
一般跟移除的對(duì)象未釋放有關(guān)
private void button1_Click(object sender, EventArgs e)
{
tab.Remove(tabPage);
}
三、最后特別奉送一個(gè)內(nèi)存釋放的大招
[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
/// <summary>
/// 釋放內(nèi)存
/// </summary>
public static void ClearMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
調(diào)用以上API能讓你的內(nèi)存一下爆減,是不是很給力,一調(diào)用內(nèi)存就降下來(lái)了。But,先別高興太早,這其實(shí)是偽釋放,只是暫時(shí)解決內(nèi)存大量泄漏導(dǎo)致系統(tǒng)崩潰的應(yīng)急處理方案。具體原因參考:SetProcessWorkingSetSize函數(shù)的騙局,關(guān)鍵信息:物理內(nèi)存轉(zhuǎn)虛擬內(nèi)存,涉及磁盤讀寫。好處壞處都貼出來(lái)了,是否需要使用請(qǐng)君自己斟酌。
四、總結(jié)
實(shí)際上由于各個(gè)開發(fā)人員的水平跟接觸面不同,又沒(méi)有經(jīng)過(guò)統(tǒng)一的培訓(xùn)(各個(gè)人對(duì)資源釋放的理解與關(guān)注度不同,或者寫代碼時(shí)就沒(méi)考慮內(nèi)存未被釋放這種問(wèn)題),發(fā)現(xiàn)問(wèn)題的時(shí)候項(xiàng)目往往已經(jīng)做到了一個(gè)階段,系統(tǒng)也比較龐大了,這種時(shí)候才發(fā)現(xiàn)內(nèi)存泄露的問(wèn)題確實(shí)是很頭疼的。
資源泄露的場(chǎng)景往往是相互關(guān)聯(lián)的,發(fā)生最多的就是內(nèi)存泄漏,而除了寫法可能有問(wèn)題外,也可能是因?yàn)榫浔孤痘蛴脩魧?duì)象泄露引起的。
參考文章:
以上就是本次介紹的全部相關(guān)知識(shí)點(diǎn),感謝大家的學(xué)習(xí)和對(duì)腳本之家的支持。
相關(guān)文章
在一個(gè)網(wǎng)站下再以虛擬目錄的方式掛多個(gè)網(wǎng)站的方法
在一個(gè)網(wǎng)站下再以虛擬目錄的方式掛N個(gè)網(wǎng)站的方法2010-04-04
WPF數(shù)據(jù)驅(qū)動(dòng)修改綁定
這篇文章介紹了WPF數(shù)據(jù)驅(qū)動(dòng)修改綁定的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
asp.net正則表達(dá)式刪除指定的HTML標(biāo)簽的代碼
抓取某網(wǎng)頁(yè)的數(shù)據(jù)后(比如描述),如果照原樣顯示的話,可能會(huì)因?yàn)樗锩姘瑳](méi)有閉合的HTML標(biāo)簽而打亂了格式,也可能它里面用了比較讓人 費(fèi)解 的HTML標(biāo)簽,把預(yù)訂的格式攪亂.2010-09-09
.Net?WebApi中實(shí)現(xiàn)自動(dòng)依賴注入的三種方法(最新推薦)
依賴關(guān)系注入 (DI) ,是一種軟件設(shè)計(jì)模式,這是一種在類及其依賴項(xiàng)之間實(shí)現(xiàn)控制反轉(zhuǎn) (IoC)?的技術(shù), .NET 中的依賴關(guān)系注入是框架的內(nèi)置部分,與配置、日志記錄和選項(xiàng)模式一樣,這篇文章主要介紹了.Net?WebApi中實(shí)現(xiàn)自動(dòng)依賴注入的三種方法,需要的朋友可以參考下2024-03-03
ASP.NET Mvc開發(fā)之刪除修改數(shù)據(jù)
這篇文章主要介紹了ASP.NET Mvc開發(fā)中的刪除修改數(shù)據(jù)功能,感興趣的小伙伴們可以參考一下2016-03-03
ASP.NET MVC后臺(tái)參數(shù)驗(yàn)證的幾種方式
本篇文章主要介紹了ASP.NET MVC后臺(tái)參數(shù)驗(yàn)證的幾種方式 ,具有一定的參考價(jià)值,有興趣的可以了解一下。2016-12-12
使用Lucene.NET實(shí)現(xiàn)站內(nèi)搜索
提到Lucene,想必大家都有所耳聞,已經(jīng)是數(shù)年前就出現(xiàn)的開源技術(shù)。很多站點(diǎn)都是利用它搭建自己網(wǎng)站的站內(nèi)搜索。由于最近也在做數(shù)據(jù)檢索方面的東西,也學(xué)習(xí)了下Lucene.net的使用。2015-06-06

