.NET 常見內存泄漏


簡介

以前認為,.NET程序內存都是托管的,如果不是調用非托管資源,應該不會存在內存泄漏的問題,但是,最近兩天對歸檔程序內存使用分析,發現,事情不是想象的那么簡單。

 

.NET內存泄漏,更准確的說應該是對象超過生命周期而不能被GC回收。本文列舉了幾種可能導致內存泄漏的情形,並提供示例代碼,及解決方案,希望對大家有所幫助。

 

所舉的例子都是經過自己極端簡化過的,只是為了說明觀點,具體項目中遇到的情形會復雜很多,需要具體分析。

事件注冊后未解除注冊

示例代碼

程序運行時,內存使用情況如圖:

原因分析

示例代碼中,表面看起來,一次循環過后,上次new出來的對象a,不會繼續被引用到,應該被視為垃圾,下次垃圾回收的時候,會被回收掉。但是,通過實驗證明,對象a是不會被回收掉的。

 

原因是因為,對象b注冊了click事件而未銷毀,導致對象b會一直引用到a,a不會被視為垃圾被GC回收。

解決辦法

對象a生命周期結束后,解除事件的注冊,只有這樣,a所占用的內存才會在下次垃圾回收的時候被回收掉。

下圖為解除事件注冊綁定后,內存的使用情況:

靜態引用

示例代碼

如果一直調用CreateObject方法,程序運行時,內存使用情況如圖:

原因分析

靜態變量的生命周期是全局的,即程序不退出,所占用的內存一直不會被釋放掉。

解決辦法

盡量少用靜態成員,若一定要使用,注意靜態成員引用的對象是否會一直增長。

控件不使用后未銷毀

示例代碼

程序運行時,內存使用情況如圖:

原因分析

示例代碼中,控件lbl已經被移除了,表面看起來,下次循環時,該控件應該被視為垃圾,在下次垃圾回收時,被回收掉。但實驗證明,內存不會被回收掉。原因在於,控件未被真正銷毀掉。

解決辦法

控件生命周期結束之后,調用Dispose方法,確保控件能被真正銷毀掉。

下圖為調用Dispose方法后,內存的使用情況:

 

調用非托管資源而未釋放

示例代碼

原因分析

使用未托管對象之后忘記釋放。

解決辦法

對於實現了IDisposable接口的類可以使用using方式使用,或者顯示調用Dispose方法。

工具

日志輸出

窮人的工具,輸出進程內存使用量 :)

任務管理器

通過觀察任務管理器內存使用情況,查看是否存在內存泄露。

 

.NET Memory Profiler

專業的.NET性能調優工具,缺點,不是免費的 :)

參考

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM