加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

取消后,C#仍然挂钩了一个事件

发布时间:2020-12-15 17:13:54 所属栏目:百科 来源:网络整理
导读:我目前正在调试一个包含内存泄漏的大型(非常大的!)C#应用程序.它主要使用 Winforms作为GUI,尽管在WPF中制作了几个控件并使用ElementHost进行托管.到目前为止,我发现许多内存泄漏是由事件没有解开(通过调用 – =)引起的,我已经能够解决问题了. 但是,我刚遇到
我目前正在调试一个包含内存泄漏的大型(非常大的!)C#应用程序.它主要使用 Winforms作为GUI,尽管在WPF中制作了几个控件并使用ElementHost进行托管.到目前为止,我发现许多内存泄漏是由事件没有解开(通过调用 – =)引起的,我已经能够解决问题了.

但是,我刚遇到了类似的问题.有一个名为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的委托被删除它仍然会被事件引用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读