我正在追踪某些应用程序中的内存泄漏。许多表单共享相同的拼写检查器对象,因此生活在任何单独的表单中。我知道如果没有正确删除处理程序事件,这可能是内存泄漏的原因。
AddHandler和RemoveHandler对我有意义,因为很明显如果调用了AddHandler,那么应该有一个相应的RemoveHandler。但Handles关键字会自动为您删除处理程序吗?
Private Sub spellingContextMenu_Popup(ByVal sender As Object, ByVal e As System.EventArgs) Handles spellingContextMenu.Popup
在上面,如果spellingContextMenu存在很长时间但是表单死了,那么应该手动删除处理程序吗?
Microsoft自己的页面未提供有关此http://msdn.microsoft.com/en-us/library/6k46st1y.aspx#feedback
的指导答案 0 :(得分:5)
Handles 关键字基于以下假设:正常事件订阅实践可以正常工作,垃圾收集器负责收集事件源,事件订阅者和委托对象。当事件源没有超出订户时,哪个工作正常。一个很好的例子是Form中的控件,当窗体关闭时,它内部的所有控件也会死掉。因此,下一个垃圾收集将摆脱所有垃圾收集,包括由 Handles 创建的任何委托对象。无需明确取消订阅。
如果您的ContextMenu超出使用它的表单,这听起来不像您的情况。并且您确实遇到了GC问题,您的ContextMenu通过其事件处理程序在表单上保留引用,因此在收集菜单之前不会收集它。因此,使用 Handles 不是正确的解决方案,您确实需要显式调用AddHandler和RemoveHandler。
请密切关注球,不仅仅为每个表单创建一个新的ContextMenu还有什么意义吗?这简单地解决了你的问题。另一种方法是不使用事件,但使表单实现接口。你使用拼写检查器类注册表单对象,它可以监听Disposed事件,知道它应该删除引用并停止通过接口进行回调。
并且要注意VB.NET中的一个错误,如果你构建一个程序集的Debug版本,那么如果在没有连接调试器的情况下运行它,它将为每个声明为WithEvents的事件泄漏一个WeakReference。它是为实现Edit + Continue支持而创建的,您必须部署程序集的Release版本以避免此泄漏。