Важно ли утилизировать SolidBrush и Pen? - PullRequest
17 голосов
/ 30 ноября 2009

Недавно я обнаружил этот элемент управления VerticalLabel в CodeProject .

Я заметил, что метод OnPaint создает, но не удаляет объекты Pen и SolidBrush.

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

РЕДАКТИРОВАТЬ

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

Я хочу знать, какие проблемы (если они есть) можно ожидать, когда объект GDI + не расположен, как в приведенном выше примере. Понятно, что в связанном примере OnPaint может вызываться много раз, прежде чем включается сборщик мусора, поэтому существует вероятность исчерпания ручек.

Однако я подозреваю, что GDI + внутренне повторно использует дескрипторы в некоторых случаях (например, если вы используете перо определенного цвета из класса Pens, оно кэшируется и используется повторно).

Я пытаюсь понять, сможет ли подобный код в связанном примере сойти с рук, пренебрегая вызовом Dispose.

А если нет, то посмотрите образец, который продемонстрировал, какие проблемы это может вызвать.

Я должен добавить, что я очень часто ( включая документацию OnPaint на MSDN ) видел примеры кода WinForms, которые не могут располагать объекты GDI +.

Ответы [ 6 ]

5 голосов
/ 30 ноября 2009

Конечно, это имеет значение. Важно избавиться от всех экземпляров классов, которые реализуют IDisposable, когда они больше не нужны. Классы определяются как IDisposable, когда они используют неуправляемые ресурсы, то есть ресурсы операционной системы, которые не обрабатываются .NET Framework.

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

Обсуждение этой темы можно найти здесь: http://agilology.blogspot.com/2009/01/why-dispose-is-necessary-and-other.html

3 голосов
/ 13 августа 2012

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

Ниже приведен патологический случай. Я наблюдаю за своим тестовым приложением в диспетчере задач (я знаю, что он сырой) и наблюдаю за столбцами «Память» (частный рабочий набор), «Ручки», «Объекты пользователя» и «Объекты GDI». Нажатие кнопки «1» приводит к более интенсивному использованию памяти, чем нажатие кнопки «2».

Если я быстро и настойчиво нажимаю на кнопку Button1, я могу вызвать исключение System.OutOfMemoryException, когда объем памяти достигает 1,6 ГБ. Button2 никогда не поднимается выше, чем около 12 МБ, независимо от того, насколько я безумно или настойчиво нажимаю.

Я работаю на 64-битной машине win7, которая создает приложение winforms профиля клиента vs 2010 .net 4. Очевидно, что вы никогда не создадите миллионы и миллионы кистей ...

С уважением, Дэвид

private void button1_Click(object sender, EventArgs e) {
    for (int i = 0; i < 500000; i++) {
        SolidBrush b = new SolidBrush(Color.FromArgb(2, 32, 43, 128));
    }       
}

private void button2_Click(object sender, EventArgs e) {
    for (int i = 0; i < 500000; i++) {
        using (SolidBrush b = new SolidBrush(Color.FromArgb(2, 32, 43, 128))) {
        }
    }
}
3 голосов
/ 10 ноября 2010

FWIW, в GDI есть «стоковые» объекты. При создании стокового объекта его не нужно удалять, поскольку он «принадлежит» ОС.

Вы, вероятно, уже знаете о фондовых объектах, но вот ссылка , в которой есть некоторые детали.

Я не знаю, есть ли в GDI + похожие "стандартные" объекты. Я только что провел краткий поиск и не нашел никаких ссылок на такие.

В качестве теста я написал небольшую программу WinForms с обратным вызовом по таймеру (включаемую каждые 10 миллисекунд), например:

private void timer1_Tick(object sender, EventArgs e)
{
  byte r = (byte)rnd.Next(0, 256);
  byte g = (byte)rnd.Next(0, 256);
  byte b = (byte)rnd.Next(0, 256);

  System.Drawing.SolidBrush sb = new SolidBrush(Color.FromArgb(0,r,g,b));
}

Если я позволю ему работать, он будет медленно потреблять память. Наблюдая за TaskManager (не самым точным способом измерить его), потребление памяти имеет тенденцию к росту (на моей машине, построенной с .NET 4.0 VS2010, Release) примерно 20 Кбайт на обновление диспетчера задач (при максимальной частоте обновления). Если я вызываю Dispose для кисти, использование памяти имеет тенденцию к увеличению примерно на 8 Кб за обновление диспетчера задач.

Вряд ли это окончательный тест, но, похоже, он указывает на большее использование памяти с течением времени, если SolidBrush не утилизируется. Интересно, что ни я, ни дескрипторы, ни объекты GDI вообще не увеличивались при выполнении теста (в любом случае). Основываясь на прошлом опыте с утечкой ресурсов GDI, я ожидал увидеть рост объектов GDI, особенно в случае с Unpose.

В любом случае, может быть, это было информативно, а может и нет.

1 голос
/ 30 ноября 2009

Это просто утечка неуправляемых ресурсов (пера / кисти) до тех пор, пока соответствующий управляемый объект не будет утилизирован сборщиком мусора. Таким образом, вы теряете несколько ручек, которые больше не используются впоследствии.

Это не слишком большая сделка, потому что Finalize() вызовет Dispose(), но освобождение неуправляемых ресурсов обычно должно быть сделано скорее раньше, чем позже.

1 голос
/ 30 ноября 2009

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

Самый простой способ продемонстрировать, происходит ли это (без внесения каких-либо изменений в код), состоит в том, чтобы использовать большое количество этих элементов управления в форме и посмотреть, продолжает ли память, используемая приложением, расти или оставаться стабильной.

0 голосов
/ 30 ноября 2009

Кроме того, я бы сказал, что предпочтительнее использовать готовые коллекции: System.Drawing.Pens. а также System.Drawing.Brushes. если вы не настроите их особым образом.

...