原文: WPF不明記憶體洩露已解決,白頭發也沒了 在使用 OpenExpressApp 進行WPF應用開發過程中遇到多個記憶體洩漏的地方,在上一篇中求助了一個記憶體洩露問題 【WPF不明記憶體洩露原因,頭發都白了幾根】 ,本篇與大家分享一下如何解決此問題的過程。
問題發現
使用者使用産品時,使用久了會報出記憶體溢出錯誤,于是開始查找記憶體洩露問題。在【
WPF -.Net 4.0解決了DataGrid分組時的記憶體洩露】中介紹了一個DataGrid記憶體洩露問題,這裡主要說的是關閉子產品後對象仍沒有釋放的問題。
問題解決
這個問題在本周之前已經由另一同僚使用
ANTS Memory Profiler 5檢視定位到是Button導緻,但是原因不明。由于記憶體洩漏不是小問題,是以我決定這周看看。
繼續查找原因
使用
檢視記憶體洩露問題,找到問題是在Button上,但是搞不清為什麼會在button上,特别是加上了WPF的DependencyObject的一些東西,如果想要弄明白覺得還不簡單。周一開始有時間我就對這個問題進行定位,但是到今天仍舊沒有頭緒:( 于是開始找其他辦法。

-
使用其它記憶體洩露工具看看
網上google了一下記憶體洩露工具,随便點選一個,下載下傳了
Scitech memory profiler 試用版本,建立項目後跑了一下程式,關閉子產品後拍了一個快照,在Type Details頁簽輸入ProjectList類庫,顯示下圖,其路徑和上圖路徑是一樣的:但是這個工具好在可以看到調用堆棧(可能 ANTS Memory Profiler 也有這個功能,隻是我不知道),切換幾個類檢視堆棧,找到了在OpenExpressApp中的類庫,高興阿,如下圖:WPF不明記憶體洩露已解決,白頭發也沒了 從上圖可以看出可能是在ButtonCommand.SetCommand中代碼導緻洩漏的。WPF不明記憶體洩露已解決,白頭發也沒了 - 今天上午發帖【
】
很感謝很多朋友馬上給我回複,其中
李永京 肯定是有經驗的高手,通過我的一個圖就能猜出問題所在,我想以前他也一定受到這個的困擾。他的回複是這樣的:LZ 是不是用DependencyPropertyDescriptor.FromProperty
這樣得到屬性然後用
AddValueChanged加了委托跟蹤屬性值的變化,最後在unload的時候去掉下。
這個是猜測,沒有具體代碼也很難分析。
解決辦法
通過上面的查找,基本定位可能出現在跟蹤屬性值變化的AddValueChanged中,檢視項目代碼,發現的确使用了
于是google搜尋【PropertyDescriptor AddValueChanged leak】,看到了一篇于此相關的blog:
PropertyDescriptor AddValueChanged Alternative。看了一下這篇文章,知道是由于事件強引用導緻,blog中也提出了一個解決辦法,就是建立一個
PropertyChangeNotifier類,通過弱引用對象建立屬性值更改事件的綁定,具體代碼和說明參考這篇bolg即可
,我就不再詳述了。
問題定位了,解決方法也有了,于是開始動刀修改問題:全文搜尋一下 DependencyPropertyDescriptor.FromProperty,發現有兩處使用了,都是OpenExpressApp中引用的外部代碼,一個是封裝Command的ButtonCommand,一個限制ListView寬度的ViewLayoutManager,代碼修改如下所示:(大家也可以通過
WeakEventManager來解決)
//memory leak, use PropertyChangeNotifier
//DependencyPropertyDescriptor.FromProperty(
// Button.IsEnabledProperty,
// typeof(Button)).AddValueChanged(button, ButtonIsEnabledChanged);
PropertyChangeNotifier notifier = new PropertyChangeNotifier(button, "IsEnabled");
notifier.ValueChanged += new EventHandler(ButtonIsEnabledChanged);
代碼修改後再跑測試,發現已經找不到這個對象了,終于解決了這個問題了:) 開始着手尋找其它記憶體洩漏問題了,不過現在有
應該能夠更快定位了。
回顧
- 事件強引用是.Net下記憶體洩漏的常出現的由于編碼不注意導緻的問題
Leak Description | Developer Error |
Improper Use of Event Handlers | X |
Improper Use of Data Binding | |
Improper Use of Command Binding | |
Improper Use of Static Event Handlers |
- 設定任務timebox,到時還未解決,可以嘗試其它工具方法:例如使用其它工具;尋求有經驗的熱心人幫忙