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