但是,我刚遇到了类似的问题.有一个名为WorkItem(短期)的类,它在构造函数中注册到另一个名为ClientEntityCache(long long)的类的事件.这些事件从来没有被解开,我可以在.NET Profiler中看到WorkItem的实例在不应该因为这些事件而保持活着状态.所以我决定使WorkItem实现IDisposable,并在Dispose()函数中以这种方式取消事件:
public void Dispose() { ClientEntityCache.EntityCacheCleared -= ClientEntityCache_CacheCleared; // Same thing for 10 other events }
编辑
public WorkItem() { ClientEntityCache.EntityCacheCleared += ClientEntityCache_CacheCleared; // Same thing for 10 other events }
我还更改了取消注册的代码,以便不调用新的EntityCacheClearedEventHandler.
编辑结束
我在使用WorkItem的代码中的适当位置调用了Dispose,当我调试时,我可以看到该函数真正被调用,而且我做 – =对于每个事件.但是我仍然得到内存泄漏并且我的WorkItems在Disposed之后仍然存活,并且在.NET分析器中我可以看到实例保持活动,因为事件处理程序(如EntityCacheClearedEventHandler)仍然在它们的调用列表中有它们.我试图解开它们不止一次(倍数= =)只是为了确保它们不会被钩住多次,但这没有用.
任何人都知道为什么会这样或者我能做些什么来解决问题?
我想我可以更改事件处理程序以使用弱委托,但这需要用大量遗留代码来搞乱.
谢谢!
编辑:
如果这有帮助,这是.NET Profiler描述的根路径:
很多东西都指向ClientEntityCache,它指向EntityCacheClearedEventHandler,它指向Object [],它指向EntityCacheClearedEventHandler的另一个实例(我不明白为什么),它指向WorkItem.
解决方法
// Simple class to host the Event class Test { public event EventHandler MyEvent; } // Two different methods which will be wired to the Event static void MyEventHandler1(object sender,EventArgs e) { throw new NotImplementedException(); } static void MyEventHandler2(object sender,EventArgs e) { throw new NotImplementedException(); } [STAThread] static void Main(string[] args) { Test t = new Test(); t.MyEvent += new EventHandler(MyEventHandler1); t.MyEvent += new EventHandler(MyEventHandler2); // Break here before removing the event handler and inspect t.MyEvent t.MyEvent -= new EventHandler(MyEventHandler1); t.MyEvent -= new EventHandler(MyEventHandler1); // Note this is again MyEventHandler1 }
如果在删除事件处理程序之前中断,则可以在调试器中查看调用列表.如下所示,有2个处理程序,一个用于MyEventHandler1,另一个用于MyEventHandler2方法.
现在两次删除MyEventHandler1之后,MyEventHandler2仍然被注册,因为只有一个委托,它看起来有点不同,它不再显示在列表中,但是直到MyEventHandler2的委托被删除它仍然会被事件引用.