.Net記憶體泄露

.Net記憶體泄露,是一種IT術語,意為基於net開發軟體時的記憶體bug事件。

基本介紹

什麼是.Net記憶體泄露,.Net記憶體泄露的檢測,記憶體泄露診斷工具,如何開發出更健壯的程式,4.1 Dispose()的使用,4.2 using的使用,4.3 事件的卸載,4.4 API的調用,4.6弱引用(WeakReference ),4.7析構函式(Finalize()),

什麼是.Net記憶體泄露

可能很多.Net的用戶(甚至包括一些dot Net開發者)對Net的記憶體泄露不是很了解,甚至會說.Net不存在記憶體泄露,因為“不是有GC機制嗎?----”恩,是有這么回事,它可以讓你在通常套用中不用考慮令人頭疼的資源釋放問題,但很遺憾的是這個機制不保證你開發的程式就不存在記憶體泄露。甚至可以說,dot Net中記憶體泄露是很常見的。這是因為: 一方面,GC機制本身的缺陷造成的;另一方面,Net中託管資源非託管資源的處理是有差異的,託管資源的處理是由GC自動執行的(執行時機是不可預知的),而非託管資源 (占少部分,比如檔案操作,網路連線等)必須顯式地釋放,否則就可能造成泄露。綜合起來說的話,由於託管資源在Net中占大多數,通常不做顯式的資源釋放是可以的,不會造成明顯的資源泄露,而非託管資源則不然,是發生問題的主戰場,是最需要注意的地方。 另外,很多情況下,衰老測試主要關注的是有沒有記憶體泄露的發生,而對其他泄露的重視次之。這是因為,記憶體跟其他資源是正相關的,也就是說沒有記憶體泄露的發生,其他泄露的發生機率也較小,其根本原因在於幾乎所有的資源最後都會在記憶體上有所反應。

.Net記憶體泄露的檢測

有沒有記憶體泄露的發生?判斷依據是那些?
原因是: 一方面,GC機制本身的缺陷造成的;另一方面,Net中託管資源非託管資源的處理是有差異的。
如果程式報“Out of memory”之類的錯誤,事實上也占據了很大部分的記憶體,應該說是典型的記憶體泄露,這種情況屬於徹底的Bug,解決之道就是找到問題點,改正。但我的經驗中,這種三下兩下的就明顯的泄露的情況較少,除非有人在很困的情況下編碼,否則大多是隱性或漸進式地泄露,這種需經過較長時間的衰老測試才能發現,或者在特定條件下才出現,對這種情況要確定問題比較費勁,有一些工具(詳見1.3)可以利用,但我總感覺效果一般,也可能是我不會使用吧,我想大型程式估計得無可奈何的用這個,詳細的參見相關手冊。
需要強調的是,判斷一個程式是不是出現了"memory leak",關鍵不是看它占用的記憶體有多大,而是放在一個足夠長的時期(程式進入穩定運行狀態後)內,看記憶體是不是還是一直往上漲,因此,剛開始的漲動或者前期的漲動不能做為泄露的充分證據。
以上是些比較感性的說法,實際操作中是通過一些性能計數器來測定的。大多數時候,主要關注Process 里的以下幾個指標就能得出結論,如果這些量整體來看是持續上升的,基本可以判斷是有泄露情況存在的。
A.Handle Count
B.Thread Count
C.Private Bytes
D.Virtual Bytes
E.Working Set
F.另外.NET CLR Memory下的Bytes in all heaps也是我比較關注的。
通過觀察,如果發現這些參數是在一個區間內震盪的,應該是沒有大的問題,但如果是一個持續上漲的狀態,那就得注意,很可能存在記憶體泄露。

記憶體泄露診斷工具

3.1如何測定以上的性能計數器
大多使用windows自帶的perfmon.msc
3.2其他一些重要的性能計數器
重要的計數器
3.3其他檢測工具
用過的工具裡面CLRProfiler 和dotTrace還行,windeg也還行。不過坦白的說,準確定位比較費勁,最好還是按常規的該Dispose的加Dispose,也可以加 GC.Collect()。

如何開發出更健壯的程式

4.1 Dispose()的使用

如果使用的對象提供Dispose()方法,那么當你使用完畢或在必要的地方(比如Exception)調用該方法,特別是對非託管對象,一定要加以調 用,以達到防止泄露的目的。另外很多時候程式提供對Dispose()的擴展,比如Form,在這個擴展的Dispose方法中你可以把大對象的引用什麼 的在退出前釋放。
對於DB連線,COM組件(比如OLE組件)等必須調用其提供的Dispose方法,沒有的話最好自己寫一個。

4.2 using的使用

using除了引用Dll的功用外,還可以限制對象的適用範圍,當超出這個界限後對象自動釋放,比如

4.3 事件的卸載

這個不是必須的,推薦這樣做。之前註冊了的事件,關閉畫面時應該手動註銷,有利於GC回收資源。

4.4 API的調用

一般的使用API了就意味著使用了非託管資源,需要根據情況手動釋放所占資源,特別是在處理大對象時。 4.5繼承 IDisposable實現自己記憶體釋放接口 Net 如何繼承IDisposable接口,實現自己的Dispose()函式

4.6弱引用(WeakReference )

通常情況下,一個實例如果被其他實例引用了,那么他就不會被GC回收,而弱引用的意思是,如果一個實例沒有被其他實例引用(真實引用),而僅僅是被弱引 用,那么他就會被GC回收。

4.7析構函式(Finalize())

使用了非託管資源的時候,可以自定義析構函式使得對象結束時釋放所占資源;
對僅使用託管資源的對象,應儘可能使用它自身的Dispose方法,一般不推薦自定義析構函式

相關詞條

熱門詞條

聯絡我們