ToolStrip.Dispose()无助于避免System.ComponentModel.Component中的内存泄漏

时间:2013-10-08 12:11:06

标签: winforms memory-leaks components dispose toolstrip

开发人员知道,如果我们不强制它手动释放某些东西,WinForms ToolStrip控件的使用可能会导致托管内存泄漏。我的意思是系统静态Microsoft.Win32.SystemEvents.UserPreferenceChanged事件的内部事件处理程序。要正确释放资源,我们需要显式调用ToolStrip Dispose方法,例如在thisthis 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+(客户端配置文件)中开发。

1 个答案:

答案 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>