Утечка памяти, опять же! - PullRequest
0 голосов
/ 27 мая 2010

Пару недель назад у меня были проблемы с утечками памяти, связанными с ContextMenuStrip. Эта проблема была исправлена. Смотрите этот вопрос здесь

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

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

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

EDIT: Что касается комментариев, то, чего я не понимаю, изначально я «делал» свою собственную панель инструментов из панели и некоторых ярлыков. Метки были использованы в качестве кнопок. Никаких утечек памяти не произошло.

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

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

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

Ответы [ 2 ]

2 голосов
/ 27 мая 2010

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

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

0 голосов
/ 27 июля 2015

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

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

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

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

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

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

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

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

Реализация 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;
         }
     }

     ...
 }

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...