Использование оператора вокруг диалоговой формы для обеспечения сборки мусора

У нас есть приложение Windows Forms, которое содержит тысячи форм.

Многие из них временно отображаются в виде диалогов с помощью метода ShowDialog().

Это приложение существует уже много лет, и мы обнаружили, что многие формы не своевременно очищаются от мусора из-за различных утечек ресурсов в форме или используемых элементах управления.

В частности, мы обнаружили примеры ресурсов GDI+, которые не удаляются должным образом, хотя могут быть и другие типы утечек ресурсов, которые еще не охарактеризованы.

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

В качестве краткосрочной альтернативы мы обнаружили, что явный вызов Dispose() в форме, по-видимому, инициирует процесс сборки мусора, и форма и ее ресурсы немедленно освобождаются.

Мой вопрос заключается в том, будет ли разумным обходным путем обернуть блок ShowDialog() каждой формы в оператор using, чтобы Dispose() вызывался после отображения формы, а также будет ли это хорошей практикой для учреждения в целом?

Например, измените существующий код следующим образом:

public void ShowMyForm()
{
    MyForm myForm = new MyForm();
    myForm.ShowDialog();
}

К этому:

public void ShowMyForm()
{
    using (MyForm myForm = new MyForm())
    {
        myForm.ShowDialog();
    }
}

В нашем тестировании метод MyForm Dispose() никогда не вызывается для первого примера, но он вызывается немедленно для второго примера.

Кажется ли это разумным подходом в качестве краткосрочного обходного пути, пока мы тратим время на отслеживание каждой из конкретных проблем с ресурсами?

Существуют ли другие подходы, которые мы могли бы рассмотреть в качестве краткосрочного временного решения и/или методологий для выявления и решения таких проблем с ресурсами?


person Avalanchis    schedule 29.11.2011    source источник
comment
Да, это лучшая практика для диалогов использования и удаления. Кроме того, Dispose будет вызываться только в том случае, если вы вызываете его явно (например, через «использование»), поэтому, если у вас есть неуправляемые ресурсы, вам может потребоваться реализовать финализатор или использовать классы-оболочки, такие как различные производные от SafeHandle, чтобы убедиться, что ресурсы очищается, даже если Dispose не вызывается.   -  person Dan Bryant    schedule 29.11.2011
comment
Обратите внимание, что существует огромная разница между Dispose() и GC. Dispose — это то, что нужно сделать здесь, и он освободит неуправляемые ресурсы, но не GC.   -  person Marc Gravell    schedule 29.11.2011
comment
Примечание: использование Controls.Clear(); может привести к утечке памяти. См. комментарий Ханса здесь stackoverflow.com/a/7706549/939213.   -  person ispiro    schedule 29.11.2011


Ответы (3)


Согласно MSDN, вы должны явно вызывать Dispose в формах, отображаемых с помощью ShowDialog (в отличие от метода Show). ):

Когда форма отображается в виде модального диалогового окна, нажатие кнопки «Закрыть» (кнопка со знаком X в правом верхнем углу формы) приводит к скрытию формы, а свойству DialogResult присваивается значение DialogResult.Cancel. В отличие от немодальных форм метод Close не вызывается платформой .NET Framework, когда пользователь щелкает кнопку закрытия формы в диалоговом окне или устанавливает значение свойства DialogResult. Вместо этого форма скрыта и может быть показана снова без создания нового экземпляра диалогового окна. Поскольку форма, отображаемая в виде диалогового окна, скрыта, а не закрыта, вы должны вызвать метод Dispose формы, когда форма больше не нужна вашему приложению.

person Patrick    schedule 29.11.2011
comment
Это было очень интересно узнать, особенно потому, что это появляется прямо в тексте справки для метода Form.ShowDialog: msdn.microsoft.com/en-us/library/c7ykbedk.aspx - person Avalanchis; 29.11.2011
comment
Если Dispose не вызывается после ShowDialog, но в форме нет утечек ресурсов, будет ли она в конечном итоге удалена (до закрытия приложения)? - person Avalanchis; 29.11.2011

Для модальных диалогов следует использовать шаблон:

using ( var dlg = new MyDialog() )
{
    // other code here to initialize, etc.
    dlg.ShowDialog();
}

Поскольку MyDialog является производным от Form, а Form реализует IDisposable, этот шаблон правильно очистит ваш диалог.

Это не должен быть «краткосрочный обходной путь», а стандартный способ вызова всех ваших модальных диалогов.

Немодальные диалоги — это отдельная история. Вам нужно будет отслеживать их самостоятельно и вызывать Dispose в соответствующих точках вашего приложения.

person ahazzah    schedule 29.11.2011

В общем, это хороший способ использовать оператор using для объектов, которые реализуют IDisposable.

Небольшая примерная ситуация:

Допустим, у вас есть сторонний "компонент". Вы не можете знать, что происходит внутри, и, возможно, эти объекты создают временный файл и удаляют файл на Dispose. Если вы не вызовете Dispose() и не используете using, файл никогда не будет удален.

В вашем случае вы тоже можете это сделать, если откроете форму modal.

person dknaack    schedule 29.11.2011