2010-05-27 4 views
0

Пару недель назад у меня возникли проблемы с утечками памяти, связанными с ContextMenuStrip. Эта проблема была исправлена. See that question hereУтечка памяти, снова!

Теперь у меня возникают аналогичные проблемы с элементами управления ToolStrip. Как и в предыдущей проблеме, я создаю большое количество UserControls и добавляю их в FlowLayoutPanel. Каждый элемент управления создает ToolStrip для себя в своем конструкторе. Когда элемент управления удаляется из FlowLayoutPanel (единственная ссылка на элемент управления), кажется, что память ToolStrip не освобождается.

Однако, когда я комментирую код, который создает ToolStrip, утечки памяти не происходит.

Это такая же проблема, как и предыдущая - мне нужно установить ToolStrip в значение null? Я не понимаю, как это могло произойти с этого момента, когда элемент управления сам создает полосу, и все события кнопки и т. Д. Обрабатываются внутри него. Итак, не все ли должно быть GC'd, когда элемент управления больше не ссылается?

EDIT: Что касается комментариев, то, что я не понимаю, изначально я был «сделать» свой собственный ToolStrip из панели и некоторых лейблов. Этикетки использовались в качестве кнопок. Таким образом, утечки памяти не происходили.

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

EDIT2: Я как раз собирался опубликовать свой код, но перечитал вопрос, с которым связан Дэйв. Оказывается, это была проблема UserPreferenceChangedEvent ToolStrip. Если я установил свойство ToolStrip.Visible в false, утечки памяти не произойдет!

Теперь, могу ли я сделать это в методе Dispose? Если да, то как? Я попытался скопировать какой-то код, но получаю предупреждение о компиляции: «MyToolStrip.Dispose()« скрывает унаследованный элемент ». System.ComponentModel.Component.Dispose()« Я просто не понимаю интерфейс IDisposable.

+5

В 95% случаев вы регистрируете обработчики событий и не отменяете их регистрацию при очистке коллекции элементов управления. Это будет первое место, где я смотрю. – Juliet

+0

не уверен, что этот вопрос помогает, но тем не менее я нашел его интересным: http://stackoverflow.com/questions/620733/memory-leak-in-c – Dave

ответ

2

95% времени вы регистрируете обработчики событий и не отменяете регистрацию при каждом очистке коллекции элементов управления. Это было бы первое место, где я смотрю

(я думал, что комментарий Джульетты заслуживает того, чтобы быть ответ)

+0

Я только что добавил код, чтобы все обработчики событий были отписаны до удаления элементы управления FlowLayoutPanel и использование памяти по-прежнему растут. К сожалению, моя пробная версия Memory Profiler истекла. Я просто не знаю, что происходит. Я не знаю, попробовать еще раз использовать IDisposable (изгоняет меня, читая об этом :). Но я не понимаю, почему это необходимо в этом случае. Как я уже сказал, он работал нормально (без утечки памяти), пока я не переключился на использование ToolStrip, даже не отписавшись от событий. – Dave

0

Официально в C# утечки памяти не существует. Память освобождается некоторое время после того, как никто ее больше не использует.

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

Всякий раз, когда вы видите, что класс реализует System.IDisposable, конструктор класса считал целесообразным Dispose объект, как только он вам больше не понадобится. Таким образом, ресурсы освобождаются до того, как сборщик мусора сделает это.

Если вы не уничтожаете объект, сборщик мусора сделает это за вас ... в конце концов. Но если вы хотите освободить свои ресурсы раньше, позаботьтесь о том, чтобы вы вызывали Dispose, как только вам больше не нужен объект.

Вы говорите о пользовательских элементах управления. U пользовательский элемент управления - это элемент управления и управления System.IDisposable. Поэтому вы должны вызвать dispose.Если у вас этого не будет, потребуется некоторое время, прежде чем ресурсы будут освобождены.

Самый простой способ убедиться, что объект удалялись как только не нужно, это используя оператор:

using (var myFile = File.Create(...)) 
{ 
    myFile.Write(...) 
    ... 
} 

Myfile правильно покраснел/закрыто/утилизация/завершена, даже если у вас есть исключения или получить из блока использования по любой причине: return/break, что угодно.

Реализация System.IDisposable часто выполняется с использованием шаблона. Этот шаблон состоит из создания дополнительной функции Dispose (bool), которая вызывается функцией Dispose и Destructor. Параметр bool указывает, вы утилизируете или нет.

class TextWriter : System.IDisposable 
{ 
    private StreamWriter writer = null; 

    public TextWriter(string fileName) 
    { 
     this.writer = StreamWriter(fileName); 
    } 

    ~TextWriter() // destructor 
    { 
     this.Dispose(false); // false: I am not disposing 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); // true: I am disposing 
     GC.SuppressFinalize(this); 
     // tell the garbage collector that this object doesn't need to be 
     // finalized (destructed) anymore 
    } 

    private void Dispose(bool dispose) 
    { 
     if (this.writer != null) 
     { 
      this.writer.Dispose(); 
      this.writer = null; 
     } 
    } 

    ... 
} 

Лично мне никогда не приходилось использовать булево средство. Официально говорится:

Настоящий выпуск освобожденных управляемых и неуправляемых ресурсов; false, чтобы освободить только неуправляемые ресурсы.

Но я не могу думать, почему я не хочу выпускать управляемые ресурсы.

Если вы получили предупреждение о том, что ваш Dispose() скрывает другой Dispose(), вы, вероятно, наследуете что-то, что реализует System.IDisposable. В этом случае вам не нужен деструктор и Dispose(), вам понадобится Dispose (bool). Посмотрите его в MSDN, и вы увидите, что можете его переопределить.

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