2013-10-08 3 views
0

Разработчики знают, что использование управления WinForms ToolStrip может привести к утечке управляемой памяти, если мы не заставим его вручную отпустить некоторые вещи. Я имею в виду внутренний обработчик событий системы static Microsoft.Win32.SystemEvents.UserPreferenceChanged. Чтобы правильно освободить ресурсы, нам нужен явный вызов метода ToolStrip Dispose, как описано, например, в this или this SO сообщения.ToolStrip.Dispose() не помогает избежать утечки памяти в System.ComponentModel.Component

Однако это не поможет, если мы используем ToolStrip от потомка System.ComponentModel.Component - по крайней мере, в моем случае. Вот соответствующая часть кода:

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), поскольку обработчик события UserPreferenceChanged должен быть удален ToolStrip автоматически в этом случае. Да, при этом вызывается внутренний метод HookStaticEvents, который должен выполнять работу. но это также не помогает.

Я даже пытался отделить обработчик события проблемы вручную с помощью отражения:

RemoveHandler Microsoft.Win32.SystemEvents.UserPreferenceChanged, _ 
    DirectCast(_ 
    System.Delegate.CreateDelegate(GetType(Microsoft.Win32.UserPreferenceChangedEventHandler), fToolStripMain, "OnUserPreferenceChanged"), _ 
     Microsoft.Win32.UserPreferenceChangedEventHandler _ 
    ) 

, но это также не имеет никакого эффекта.

Любые идеи о том, как преодолеть эту проблему утечки памяти в нашем случае и почему явный вызов ToolStrip.Dispose может не работать в нашем случае?

Мы разрабатываем в VB.NET 2010 для .NET Framework 4+ (профиль клиента).

ответ

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, мне очень помог в поиске решения - BTW, не тратя ни копейки на покупку профайлов коммерческой памяти.

 Смежные вопросы

  • Нет связанных вопросов^_^