【譯】解開託管內存的祕密:深入瞭解事件處理程序泄漏!

  事件處理程序泄漏已經存在很長時間了,這是 WPF (Windows Presentation Foundation)開發人員經常要處理的最麻煩的問題之一。您可能會想:是什麼讓事件處理程序泄漏如此重要?事件處理程序泄漏很容易引起,只需忘記取消訂閱事件即可。此外,它們很難發現,甚至更難修復。

  在更新17.9預覽1中引入的 Visual Studio 託管內存使用工具中添加的新見解大大簡化了發現/修復這些泄漏的過程。它提供有關哪些對象正在泄漏及其訂閱的事件的信息。

什麼是事件處理程序泄漏?

  當對象在功能上無法使用時,沒有被識別爲垃圾收集時,它會在堆上泄漏。這意味着它將無意中在內存中保持活動狀態。事件處理程序因導致這種情況而臭名昭著。這是因爲事件處理程序在對象和它訂閱的事件之間創建了一個直接引用。

  在本例中,我們有一個 Publisher 和 Subscriber 類。當 Subscriber 調用 Subscribe 時,MyEvent 將在堆中鏈接 Publisher 和 Subscriber:

  這樣做的問題是,如果 Subscriber 忘記取消訂閱,這些引用將保留在堆上,從而泄漏 Subscriber。這裏最簡單的解決方案是簡單地調用 Unsubscribe 方法,但是在更復雜的應用程序中,很難跟蹤對象的訂閱以及何時退訂。這就是 Memory Analyzer 可以幫助開發人員解決這些問題的地方。

好吧,讓我們看看如何解決它?

  爲了證明這一點,我們將對一個示例 WPF 應用程序進行演練調試,以查找事件處理程序泄漏:

  在本例中,我們有一個窗口,它在打開時訂閱 dispatcherTimer_Tick 事件。事件在做什麼並不重要。這段代碼的重要部分是,當窗口關閉時,我們忘記取消訂閱事件:

  這裏取消訂閱語句的註釋是有問題的,因爲它在窗口關閉時不再正確地取消訂閱,並且會導致泄漏。爲了找到它,讓我們開始調試這個應用程序(F5)。爲簡單起見,讓我們假設 main() 正確地導致泄漏,它打開 AdWindow,導致它訂閱一個事件,然後關閉它。

  首先,我們需要打開診斷工具窗口。要在調試會話中訪問它,請執行 Debug ->  Windows ->  Diagnostic Tools。

  當它在調試會話中打開時,它應該是這樣的:

  此窗口顯示正在調試的應用程序的堆的總體大小和 CPU 百分比。當我們單擊相機圖標拍攝快照時,我們可以通過單擊 Objects 下的值來查看堆並訪問事件處理程序泄漏見解。

  進入快照的堆視圖後,導航到 Insights(見解):

  我們終於到站了!在 Insights 選項卡中,我們可以看到泄漏事件處理程序的列表,並且我們可以看到泄漏窗口的顯示。此外,我們可以看到該泄漏所浪費的總量。僅僅是這個簡單的例子就造成了 4.93 KB 的泄漏!這是因爲窗口有一個完整的子樹,它引用的對象也會因爲忘記取消訂閱而泄漏。

  此外,您可以通過點擊“Show Just My code”來過濾掉所有的系統代碼,只顯示 AdWindow。

  這很酷,但現在怎麼辦?

  到目前爲止,我們已經成功地確定了我們的應用程序中的泄漏。現在,如果我們想要修復它,我們可以點擊“View Details”來查看有關問題的更多信息,更重要的是,如何修復它。

  這個視圖向我們展示了一些關於泄漏的關鍵信息。我們可以看到對象的地址,它持有的事件處理程序,最重要的是,它訂閱的對象。這傳達了要解決這個問題,AdWindow 必須從 DispatcherTimer 取消訂閱。此外,您還可以看到 AdWindow 對象的引用圖。“Referenced Objects”選項卡顯示了由於 AdWindow 而泄漏的額外對象的數量。

我們還能做什麼?

  如果您已經讀到這裏了,你可能會對這種見解的其他用途感興趣。例如,檢測邏輯可以處理任何類型的事件處理程序。考慮前面的帶有發佈者和訂閱者類的控制檯應用程序,如果我們創建自己的事件處理程序,我們仍然可以檢測到它。

告訴我們您的想法!

  在未來的版本中,這種體驗還會有很多改進。請下載最新的 Visual Studio 預覽版並提供您的反饋。請在 Visual Studio 中通過“Report a Problem”或直接在開發者社區站點提出問題並提供反饋。

 

原文鏈接:https://devblogs.microsoft.com/visualstudio/unlocking-the-secrets-of-managed-memory-dive-into-event-handler-leak-insights/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章