西西軟件下載最安全的下載網(wǎng)站、值得信賴的軟件下載站!

首頁(yè)業(yè)內(nèi)動(dòng)態(tài) 業(yè)內(nèi)資訊 → 預(yù)防.NET應(yīng)用程序OOM的經(jīng)驗(yàn)備忘

預(yù)防.NET應(yīng)用程序OOM的經(jīng)驗(yàn)備忘

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2013/3/5 20:50:35字體大。A-A+

作者:西西小熊點(diǎn)擊:0次評(píng)論:1次標(biāo)簽: OOM

  • 類型:壁紙主題大。850KB語(yǔ)言:英文 評(píng)分:5.0
  • 標(biāo)簽:
立即下載

根據(jù)個(gè)人的開發(fā)和系統(tǒng)調(diào)優(yōu)經(jīng)驗(yàn),大部分的內(nèi)存泄露都和不好的開發(fā)習(xí)慣有直接關(guān)系,有幾個(gè)開發(fā)經(jīng)驗(yàn)可以有效預(yù)防OOM,總結(jié)下貼出來(lái)和大家分享。

一、批量和分頁(yè)

老生常談的話題,簡(jiǎn)單,但是非常實(shí)用。

每個(gè)合格的coder對(duì)數(shù)據(jù)的處理,必須要有分頁(yè)或批量多次的意識(shí)。大數(shù)據(jù)量的讀取或查詢結(jié)果集是內(nèi)存占用大戶,是系統(tǒng)性能下降的直接原因之一。

在典型的互聯(lián)網(wǎng)web應(yīng)用中,數(shù)據(jù)量較大且高并發(fā)的情況下,不分頁(yè),或者不進(jìn)行批量處理,每次總是取出很多用戶數(shù)據(jù),很容易造成內(nèi)存開銷過(guò)大,系統(tǒng)內(nèi)存吃緊。再比如我們有時(shí)候進(jìn)行文件操作,讀取文件內(nèi)容的時(shí)候就要斟酌考慮文件有多大。

如果你的項(xiàng)目中還在出現(xiàn)不分青紅皂白一次查詢返回N(N有多大?)條記錄的DataSet、DataTable或者列表記錄等等情況,或者查詢大量數(shù)據(jù)寫入臨時(shí)表,或者一次讀取很大文件內(nèi)容......呵呵。


二、慎用靜態(tài)

這個(gè)也是常見(jiàn)但是比較隱式的引起內(nèi)存泄露的元兇之一。

靜態(tài)類、靜態(tài)字段、靜態(tài)屬性,靜態(tài)委托,靜態(tài)方法…靜態(tài)的好處當(dāng)然顯而易見(jiàn),比如調(diào)用方便,常駐內(nèi)存提高性能等等,所以,有些代碼索性靜態(tài)到底,除了實(shí)體層,在表現(xiàn)層(說(shuō)起來(lái)非?膳,我曾經(jīng)在web應(yīng)用程序中看到竟然有人名目張膽地大肆使用靜態(tài)字段),數(shù)據(jù)訪問(wèn)層、業(yè)務(wù)邏輯層、公共組件、配置管理等等等等,能靜態(tài)的全給它用上靜態(tài)。

比起大數(shù)據(jù)查詢?cè)斐傻某0l(fā)性的內(nèi)存不足,使用靜態(tài)太多的應(yīng)用程序一時(shí)半會(huì)也不會(huì)內(nèi)存泄露。可隨著系統(tǒng)的運(yùn)行,靜態(tài)的東西越來(lái)越多,內(nèi)存開銷也就越大,由于GC的回收策略,無(wú)效的靜態(tài)所占內(nèi)存又不容易及時(shí)釋放,久而久之就造成了內(nèi)存不足。

使用靜態(tài)的情況在分層應(yīng)用程序中非常常見(jiàn),而且由于它的好處容易得到體現(xiàn)而隱藏的風(fēng)險(xiǎn)不容易暴露出來(lái),所以很多程序員還是非常執(zhí)著地使用靜態(tài)。


三、二方庫(kù)、三方庫(kù),非托管資源,優(yōu)先使用Dispose模式

有些應(yīng)用程序需要借助包裝的二方庫(kù)或者三方庫(kù),或者使用了非托管資源,如com組件等等,由于.NET自動(dòng)內(nèi)存管理和回收,很多人覺(jué)得我用一下完成功能就Over了。

實(shí)際情況是你調(diào)用了別人的庫(kù),別人的庫(kù)也很可能當(dāng)仁不讓地占用了你的內(nèi)存而你還不自知。

每次調(diào)用別人的資源都應(yīng)該有個(gè)警覺(jué)性:用你的類庫(kù)可以,占用我的(內(nèi)存)不行。

如果你熟悉自動(dòng)內(nèi)存管理,熟悉GC,理解Dispose模式,那么一定會(huì)在調(diào)用別人的資源的時(shí)候想著還是using一下為妙,或者,強(qiáng)制賦個(gè)null也是舉手之勞,要相信某些良好的編程習(xí)慣可以讓自動(dòng)內(nèi)存管理更有效。怕的就是很多人拿來(lái)主義,測(cè)試不充分,自己調(diào)用成功功能完成開發(fā)就OK了,交接給別人自己走人。


四、減少字符串臨時(shí)對(duì)象

這個(gè)實(shí)在是太熟悉不過(guò)了,不論是什么形式的應(yīng)用程序,哪里能少得了字符串的身影?

看到它們有人條件反射似地想到拼接字符串,想到駐留池等等等等。

沒(méi)錯(cuò),不合理地使用String進(jìn)行操作也會(huì)造成內(nèi)存不足異常,而且這絕不是聳人聽聞。

舉例來(lái)說(shuō),對(duì)于String的+=,很多應(yīng)用程序中這個(gè)操作層出不窮。我們都知道+=操作會(huì)造成很多臨時(shí)字符串對(duì)象,這些對(duì)象由于CLR對(duì)字符串的駐留處理,容易占用內(nèi)存空間。如果是高并發(fā)的web應(yīng)用程序,而字符串操作隨處可見(jiàn),且字符串的長(zhǎng)度又不確定地長(zhǎng),前端頁(yè)面各種各樣的拼接,久而久之,內(nèi)存占用就會(huì)是一個(gè)重大問(wèn)題。CLR對(duì)字符串的優(yōu)化處理使得字符串不被優(yōu)先回收,如果字符串操作頻繁,臨時(shí)字符串較長(zhǎng)(比如大于等于85000字節(jié))而出現(xiàn)大對(duì)象堆的分配,那么更容易出現(xiàn)內(nèi)存泄露。

很多人可能都會(huì)想到如何優(yōu)化程序去降低string的臨時(shí)對(duì)象的生成概率。對(duì)的,StringBuilder的出現(xiàn)就順理成章了。


五、其他經(jīng)驗(yàn)

1、Session的不當(dāng)使用,尤其是使用InProc模式的會(huì)話,為了保持狀態(tài)而選擇使用Session,如用戶訪問(wèn)量較大將極大消耗服務(wù)器資源,而且會(huì)出現(xiàn)Session丟失的不穩(wěn)定現(xiàn)象,所以一般的站點(diǎn)都選擇restful的無(wú)狀態(tài)服務(wù);

2、使用較為復(fù)雜的數(shù)據(jù)結(jié)構(gòu),比如字典里面嵌套字典,字典的鍵和值也使用字典,曾經(jīng)碰到過(guò)一個(gè)非常奇葩的項(xiàng)目,至少5層字典嵌套…有人會(huì)反駁說(shuō)字典是引用類型,而且自動(dòng)垃圾回收等等等等等等,在OOM面前一切雄辯都蒼白無(wú)力;

3、過(guò)深的繼承鏈,這里尤其要說(shuō)的是類繼承,熟悉垃圾回收的應(yīng)該都清楚GC回收原理,繼承的存在有可能延長(zhǎng)類的生命周期而不利于及時(shí)回收,所以,如果實(shí)際項(xiàng)目中出現(xiàn)繼承的深度超過(guò)兩位數(shù),那一定是抽象出現(xiàn)問(wèn)題了,重構(gòu)是必然選擇;

4、一些多媒體處理程序的開發(fā)中內(nèi)存泄露情況也非常常見(jiàn),比如使用GDI+開發(fā)畫圖程序等等,內(nèi)存消耗嚴(yán)重,這時(shí)候托管代碼開啟dispose模式無(wú)比重要;

5、在使用lucene.net的過(guò)程中發(fā)現(xiàn)有時(shí)候創(chuàng)建索引會(huì)出現(xiàn)OOM,數(shù)據(jù)量上去以后,內(nèi)存不足幾乎不可避免,這個(gè)時(shí)候就必須考慮重新調(diào)整架構(gòu)拆分索引文件分布處理了;

6、有時(shí)候調(diào)用office組件進(jìn)行一些報(bào)表處理,發(fā)現(xiàn)內(nèi)存好像一下子少了好多?使用7z壓縮組件,如果多線程調(diào)用,好像也有內(nèi)存吃緊的現(xiàn)象?

7、調(diào)用第三方郵件組件處理郵件和附件,CPU和內(nèi)存開銷都很不能讓人滿意;

……

更多其他容易導(dǎo)致OOM的開發(fā)經(jīng)驗(yàn)等你來(lái)補(bǔ)充。


六、警惕大對(duì)象

本文前面分析的幾種情況流于經(jīng)驗(yàn)和表象,還有一種直達(dá)問(wèn)題本質(zhì)的內(nèi)存泄露原因需要分析。

如果你深入理解了內(nèi)存回收原理以及大對(duì)象和大對(duì)象堆(Large Object Heap,LOH),那么大對(duì)象導(dǎo)致的內(nèi)存碎片化問(wèn)題就很好理解了。

簡(jiǎn)單來(lái)說(shuō):

1、任何大于等于85000字節(jié)的對(duì)象都被自動(dòng)視為大對(duì)象,大對(duì)象從特殊的大對(duì)象堆中分配。大對(duì)象堆和小對(duì)象堆一樣進(jìn)行終結(jié)和釋放,但是GC回收算法從來(lái)不對(duì)大對(duì)象堆(Large Object Heap)進(jìn)行內(nèi)存壓縮整理,因?yàn)樵诙阎邢乱?5000字節(jié)或更大的內(nèi)存塊會(huì)浪費(fèi)太多的CPU時(shí)間;

2、在.NET中,CLR采用基于代(generation)的垃圾回收,大對(duì)象總被認(rèn)為是第2代(generation)的一部分,GC分析哪些對(duì)象不可達(dá),優(yōu)先分析第0代和第1代,第2代的對(duì)象通常被認(rèn)為長(zhǎng)時(shí)間存活。

正是由于1和2所述的兩個(gè)原因(主要原因還是第1個(gè)),在垃圾回收過(guò)程中容易造成內(nèi)存碎片。這里推薦一篇老外寫的流傳甚廣的文章供參考:the dangers of the LOH

隨著應(yīng)用程序的運(yùn)行,如果LOH導(dǎo)致的內(nèi)存碎片越來(lái)越多,內(nèi)存有效使用率下降會(huì)非常嚴(yán)重,比如我們?cè)趙eb應(yīng)用程序中+=拼接字符串(見(jiàn)第4條的分析),如果大于等于85000字節(jié)的字符串臨時(shí)對(duì)象很多,那么用戶量一上去,隨著系統(tǒng)的運(yùn)行,GC回收壓力越來(lái)越大OOM的風(fēng)險(xiǎn)會(huì)變得更高。

雖然內(nèi)存碎片化導(dǎo)致的OOM看上去似乎無(wú)解,但是如果寫程序的人仔細(xì)分析解決問(wèn)題,想方設(shè)法主動(dòng)降低創(chuàng)建大對(duì)象的頻率,那么內(nèi)存泄露的可能就會(huì)降低,足夠優(yōu)秀健壯的程序不能徹底解決OOM,但是我們完全可以將風(fēng)險(xiǎn)發(fā)生的情況將至最低可能。

一個(gè)足夠合格的coder肯定需要具備充足的分析和解決OOM問(wèn)題的準(zhǔn)備和經(jīng)驗(yàn),有很多分析和檢查OOM的工具如ANTS Memory Profiler,還可以通過(guò)調(diào)試?yán)魅鐆indbg對(duì)內(nèi)存dump文件進(jìn)行分析。用好這些工具,讓OOM無(wú)所遁形也不失為解決之道。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(1)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)