gpt4 book ai didi

取消 Hook 后 C# 仍然 Hook 到事件

转载 作者:太空狗 更新时间:2023-10-29 20:25:30 28 4
gpt4 key购买 nike

我目前正在调试一个包含内存泄漏的大(非常大!)C# 应用程序。它主要使用 Winforms 作为 GUI,尽管一些控件是在 WPF 中制作的,并由 ElementHost 托管。直到现在,我发现许多内存泄漏是由于事件没有被解除 Hook (通过调用 -=)引起的,我已经能够解决这个问题。

但是,我刚刚遇到了类似的问题。有一个名为 WorkItem(短期)的类,它在构造函数中注册到另一个名为 ClientEntityCache(长期)的类的事件。这些事件永远不会解除 Hook ,我可以在 .NET 探查器中看到 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 在被处置后仍然保持事件状态,在 .NET 探查器中我可以看到实例保持事件状态,因为事件处理程序(如 EntityCacheClearedEventHandler)仍然将它们放在它们的调用列表中。我试图不止一次(多次-=)解开它们,只是为了确保它们没有被钩住不止一次,但这无济于事。

任何人都知道为什么会发生这种情况,或者我可以做些什么来解决这个问题?我想我可以更改事件处理程序以使用弱委托(delegate),但这需要处理大量遗留代码。

谢谢!

编辑:

如果这有帮助,这里是 .NET 探查器描述的根路径:很多东西指向 ClientEntityCache,它指向 EntityCacheClearedEventHandler,它指向 Object[],它指向 EntityCacheClearedEventHandler 的另一个实例(我不明白为什么),它指向 WorkItem。

最佳答案

可能是多个不同的委托(delegate)函数连接到事件。希望下面的小例子能让我更清楚地理解我的意思。

// 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。

enter image description here

现在两次删除 MyEventHandler1 后,MyEventHandler2 仍然被注册,因为只剩下一个委托(delegate)看起来有点不同,它不再显示在列表中,但在删除 MyEventHandler2 的委托(delegate)之前它仍然会被引用由事件。

enter image description here

关于取消 Hook 后 C# 仍然 Hook 到事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6141058/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com