2010-12-09 24 views
11

我在遇到內存泄漏的應用程序時遇到問題。經驗告訴我,垃圾收集語言首先遇到內存泄漏的地方之一就是處理訂閱事件並且未能在稍後取消訂閱。第二個與存儲靜態有關。我是C#的新手,對於不透明的事件類型感到沮喪。你如何找出訂閱C#中的事件?

我們通過抽獎的運氣發現了一些雙重訂閱錯誤,但應用程序確實使用了很多事件。雖然我們很清楚取消訂閱您訂閱的所有內容的原則,但仍然存在內存泄漏。我想系統地確定訂閱什麼。

編輯:

感謝您的指針GetInvocationList()方法。我正在嘗試創建一個將動態轉儲結果的調試工具。問題是我找到的解決方案在.Net 2中工作,但不再在.Net 3.5中。本質上,告訴你爲EventInfo(分別爲reflection,GetField和GetEvents)獲取相應的FieldInfo。但是,在.Net 3.5中沒有相應的FieldInfo,並且EventInfo不會讓我獲取調用列表。

我只想轉儲事件及其調用列表的調試目的列表。

+0

看到我的回答,C#事件內存泄漏,上個月類似的問題。 – 2010-12-09 16:25:47

+0

我很難選擇哪一個應該得到「官方」答案,因爲他們都滿足了我需要的不同部分。最後,我選擇了標題中回答問題的人,儘管n8wrl的答案在不同的方面同樣出色。 – 2010-12-10 13:30:18

回答

6

嘗試使用名爲GetInvocationListevent上的方法。

這將返回訂閱事件的代理數組。

該數組將按照它們添加的順序包含代表。這也可以用來從列表中選出和調用特定的委託,而調用event.Invoke方法將調用它們全部(但只給你所調用的最後一個委託的返回值)

1

你當然是正確的 - 懷疑事件訂閱是導致內存泄漏的原因。幾年前,我們追蹤了一個應用程序範圍的靜態對象訂閱ASP.NET頁面事件的問題 - 您可以猜測發生了什麼。

解決這個問題的另一種方法是從出版商的角度出發。將所有訂閱者都訂閱到UN訂閱可能並不方便,但是如果發佈者需要銷燬/超出範圍,也許可以觸發它將所有事件設置爲空 - 有效地取消訂閱所有人並打破循環。

如果發佈者擁有更長的生命週期並且保持其他對象存活,您可能必須執行前面提到的GetInvocationList事情。但我認爲這只是爲了調試問題 - 找出誰不應該掛在事件上。

最後,您可以考慮一些基於WeakReferenced的自定義事件訂閱機制。

0

請參閱this blog post,以便在Watch窗口中查看事件訂閱者的有用轉儲。