开发人员知道,如果我们不强制它手动释放某些东西,WinForms ToolStrip控件的使用可能会导致托管内存泄漏。我的意思是系统静态Microsoft.Win32.SystemEvents.UserPreferenceChanged
事件的内部事件处理程序。要正确释放资源,我们需要显式调用ToolStrip Dispose方法,例如在this或this SO帖子中描述。
但是,如果我们使用System.ComponentModel.Component后代的ToolStrip,这没有任何帮助 - 至少在我的情况下。这是代码的相应部分:
Private Class DropDownFilterBox
Inherits System.ComponentModel.Component
Private WithEvents fToolStripMain As New AutoFilterToolStrip
Private WithEvents fToolStripOKCancel As New AutoFilterToolStrip
Private WithEvents fContextMenuStripCustomFilterOperators As New ContextMenuStrip
Private WithEvents fToolStripDropDownCustomFilterDatePicker As New ToolStripDropDown
Private WithEvents fToolStripControlHostCustomFilterDatePicker As New AutoFilterToolStripControlHostDatePicker
.......................
Public Overloads Sub Dispose()
fToolStripMain.Dispose()
fToolStripOKCancel.Dispose()
fContextMenuStripCustomFilterOperators.Dispose()
fToolStripDropDownCustomFilterDatePicker.Dispose()
fToolStripControlHostCustomFilterDatePicker.Dispose()
MyBase.Dispose()
End Sub
End Class
AutoFilterToolStrip的定义如下:
Private Class AutoFilterToolStrip
Inherits ToolStrip
......................
End Class
,但这在我们的背景下无关紧要。
我甚至会在需要时手动调用DropDownFilterBox.Dispose来清理使用过的资源,但似乎没有任何效果。
一些开发人员建议隐藏ToolStrips(将Visible属性设置为False),因为在这种情况下,ToolStrip应自动删除UserPreferenceChanged事件处理程序。是的,在那里调用应该执行工作的内部HookStaticEvents方法。但这也无济于事。
我甚至尝试使用反射手动分离问题事件处理程序:
RemoveHandler Microsoft.Win32.SystemEvents.UserPreferenceChanged, _
DirectCast( _
System.Delegate.CreateDelegate(GetType(Microsoft.Win32.UserPreferenceChangedEventHandler), fToolStripMain, "OnUserPreferenceChanged"), _
Microsoft.Win32.UserPreferenceChangedEventHandler _
)
,但这也没有任何效果。
在我们的案例中有关如何克服此内存泄漏问题的任何想法以及为什么在我们的情况下显式调用ToolStrip.Dispose可能不起作用?
我们在VB.NET 2010 for .NET Framework 4+(客户端配置文件)中开发。
答案 0 :(得分:1)
我的代码缺少部分如下:
Dim myOverflowButton As ToolStripOverflow
myOverflowButton = DirectCast(fToolStripMain.OverflowButton.DropDown, ToolStripOverflow)
If (myOverflowButton IsNot Nothing) Then
myOverflowButton.Dispose()
End If
myOverflowButton = DirectCast(fToolStripOKCancel.OverflowButton.DropDown, ToolStripOverflow)
If (myOverflowButton IsNot Nothing) Then
myOverflowButton.Dispose()
End If
ToolStrip会自动创建所谓的溢出按钮,它还会订阅UserPreferenceChanged事件,这可能会导致内存泄漏!有关此内容的更多信息可在此处找到:ToolStrip memory leak。
现在我的组件的Dispose方法的完整列表如下所示:
Public Overloads Sub Dispose()
With fContainer.Controls
.Remove(fToolStripMain)
.Remove(fToolStripOKCancel)
End With
fToolStripMain.Visible = False
fToolStripOKCancel.Visible = False
fContextMenuStripCustomFilterOperators.Visible = False
fToolStripDropDownCustomFilterDatePicker.Visible = False
fToolStripControlHostCustomFilterDatePicker.Visible = False
fToolStripMain.Dispose()
fToolStripOKCancel.Dispose()
fContextMenuStripCustomFilterOperators.Dispose()
fToolStripDropDownCustomFilterDatePicker.Dispose()
fToolStripControlHostCustomFilterDatePicker.Dispose()
Dim myOverflowButton As ToolStripOverflow
myOverflowButton = DirectCast(fToolStripMain.OverflowButton.DropDown, ToolStripOverflow)
If (myOverflowButton IsNot Nothing) Then
myOverflowButton.Dispose()
End If
myOverflowButton = DirectCast(fToolStripOKCancel.OverflowButton.DropDown, ToolStripOverflow)
If (myOverflowButton IsNot Nothing) Then
myOverflowButton.Dispose()
End If
' Dispose calls for other used components
MyBase.Dispose()
End Sub
我还应该承认,在CodeProject文章Memory Leak Detection in .NET中描述的托管代码中发现内存泄漏的技术帮助我找到了解决方案 - 顺便说一句,花不了一分钱购买商业内存分析器。 / p>