天天看點

WPF不明記憶體洩露已解決,白頭發也沒了

原文: WPF不明記憶體洩露已解決,白頭發也沒了      在使用 OpenExpressApp 進行WPF應用開發過程中遇到多個記憶體洩漏的地方,在上一篇中求助了一個記憶體洩露問題 【WPF不明記憶體洩露原因,頭發都白了幾根】 ,本篇與大家分享一下如何解決此問題的過程。

問題發現

  使用者使用産品時,使用久了會報出記憶體溢出錯誤,于是開始查找記憶體洩露問題。在【

WPF -.Net 4.0解決了DataGrid分組時的記憶體洩露

】中介紹了一個DataGrid記憶體洩露問題,這裡主要說的是關閉子產品後對象仍沒有釋放的問題。

問題解決

  這個問題在本周之前已經由另一同僚使用

ANTS Memory Profiler 5

檢視定位到是Button導緻,但是原因不明。由于記憶體洩漏不是小問題,是以我決定這周看看。

繼續查找原因

  使用

檢視記憶體洩露問題,找到問題是在Button上,但是搞不清為什麼會在button上,特别是加上了WPF的DependencyObject的一些東西,如果想要弄明白覺得還不簡單。周一開始有時間我就對這個問題進行定位,但是到今天仍舊沒有頭緒:(  于是開始找其他辦法。

WPF不明記憶體洩露已解決,白頭發也沒了
  • 使用其它記憶體洩露工具看看

    網上google了一下記憶體洩露工具,随便點選一個,下載下傳了

    Scitech memory profiler 試用版本,建立項目後跑了一下程式,關閉子產品後拍了一個快照,在Type Details頁簽輸入ProjectList類庫,顯示下圖,其路徑和上圖路徑是一樣的:
    WPF不明記憶體洩露已解決,白頭發也沒了
    但是這個工具好在可以看到調用堆棧(可能 ANTS Memory Profiler 也有這個功能,隻是我不知道),切換幾個類檢視堆棧,找到了在OpenExpressApp中的類庫,高興阿,如下圖:
    WPF不明記憶體洩露已解決,白頭發也沒了
    從上圖可以看出可能是在ButtonCommand.SetCommand中代碼導緻洩漏的。
  • 今天上午發帖【

    很感謝很多朋友馬上給我回複,其中

    李永京 肯定是有經驗的高手,通過我的一個圖就能猜出問題所在,我想以前他也一定受到這個的困擾。他的回複是這樣的:

    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,到時還未解決,可以嘗試其它工具方法:例如使用其它工具;尋求有經驗的熱心人幫忙

相關blog

WPF不明記憶體洩露原因,頭發都白了幾根 歡迎轉載,轉載請注明:轉載自 周金根 [ http://zhoujg.cnblogs.com/ ]