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

Я понимаю, что лучше использовать Dispose() для экземпляров Pen и Brush, за исключением случаев, когда они были установлены на предопределенные системой значения (например, System.Drawing.Brushes, System.Drawing.Pens или System.Drawing.SystemBrushes)

Попытка утилизации системно-определяемого ресурса приводит к тому, что генерируется исключение.

Не кажется очевидным, как вы можете обнаружить (помимо обертывания вызова Dispose() в try/catch), ссылается ли один из этих ресурсов на системное или определяемое пользователем значение.

Ответ 1

Нет требования для вызова Dispose. Цель сбора мусора - устранить эти требования.

Одна из основных целей IDisposable - разрешить классу очищать неуправляемые ресурсы в средах с ограниченными ресурсами. Если вы не вызываете метод dispose, неуправляемые ресурсы класса будут очищены после завершения финализации объекта и его удаления во время сбора мусора.

Если вы "должны" вызывать dispose и не знаете, является ли экземпляр кисти "кистью" или "обычной" кистью, вам придется использовать блок try... catch.

  • Не нужно вызывать dispose на SystemBrushes и SystemPens, потому что библиотека GDI + позаботится об этих ресурсах.
  • Хорошо утилизировать SystemFonts и SystemIcons.

В разделе Заметки класса будет указано, требуется ли требование вызвать метод Dispose. Если в разделе "Примечания" рекомендуется вызвать метод Dispose, я сделаю это.

В общем, я не звоню на ручки и кисти. Если у меня есть приложение или класс, насыщенный графикой, я буду кэшировать экземпляры ручек и кистей, которые мне нужны. Я использую их на протяжении всей жизни приложения или класса. Если бы я этого не сделал, тогда производительность графической графики пострадает от попыток создания и удаления всех этих проектов столько раз и так часто. (Hm... теперь, когда я думаю об этом, производительность, вероятно, является причиной того, что мы не можем избавиться от SystemBrushes и SystemPens, но можем избавляться от SystemFonts и SystemIcons. Даже структура кэширует SystemBrushes и SystemPens.)

Ответ 2

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

Нет требования для вызова Dispose.

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

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

Цель сбора мусора - устранить эти требования.

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

Одна из основных целей IDisposable - разрешить классу очищать неуправляемые ресурсы в средах с ограниченными ресурсами.

Это правильно.

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

Это иногда правильно; это правильно для объектов GDI. Это хорошая практика для классов, которые держатся за неуправляемые ресурсы для реализации семантики завершения в качестве блокиратора; дополнительный уровень защиты для людей, которые следуют плохим советам, данным в принятом ответе. Вы не должны полагаться на финализаторы, чтобы избавить вас от ошибок; вы должны распоряжаться своими ресурсами.

Вы должны полагаться только на финализатор, чтобы справляться с безумными исключительными ситуациями. Рассмотрим, например:

Brush myBrush = MakeMeABrush();
DoSomethingWithBrush(myBrush);
myBrush.Dispose();

Предположим, что исключение прерывания потока выбрано после выделения кисти, но до назначения myBrush. Никакая комбинация try-catch-finally не позволит вам очистить эту кисть с помощью Dispose; вам придется полагаться на финализатор. Это то, что финализатор для: совершенно сумасшедшие ситуации, когда вы не можете распоряжаться собой. Это не повод быть неаккуратным.

Если вы "должны" вызывать dispose и не знаете, является ли экземпляр кисти "кистью" или "обычной" кистью, вам придется использовать блок try... catch.

Хотя это опять-таки, технически корректно, оно полностью не соответствует действительности. Если вы находитесь в ситуации, когда вы не знаете, есть ли у вас кисть, у вас есть ошибка в дизайне вашей программы. Не докучайте свои ошибки с помощью блока try-catch! Исправьте ошибку!

Эта ситуация является общей для всех явно управляемых ресурсов: объект, который предоставляет ресурс и объект, который потребляет ресурс, несет ответственность за четкое документирование того, кто из двух владеет очисткой ресурса. Если вы не знаете, есть ли у вас кисть, которую вы получили или нет, тогда кто-то не выполняет задачу, за которую они несут ответственность, а именно , предотвращая такую ​​ситуацию возникающие.

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

Если контракт, на который вы решаете, заключается в том, что производитель и потребитель собираются освободить ресурс, потребитель должен называть Clone на каждую пройденную кисть, чтобы гарантировать, что у них есть безопасно располагаемый ресурс, и что производитель продолжает владеть действительным ресурсом.

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

Но контракт "никто не очищает его, и мы надеемся на лучшее" - довольно плохой контракт.

Не нужно вызывать Dispose() на SystemBrushes и SystemPens, потому что библиотека GDI + позаботится об этих ресурсах.

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

В разделе "Примечания" этого класса будет указано, требуется ли требование вызвать метод Dispose.

Это утверждение ложно. Вы должны сделать предположение, что всегда необходимо Dispose a IDisposable ресурс, если у вас нет оснований полагать иначе. Отсутствие строки в документации не является доказательством того, что утилизация не нужна.

Чтобы положительно отметить:

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

Это хорошая практика. Если количество создаваемых кистей и ручек относительно невелико и одни и те же используются снова и снова, то имеет смысл кэшировать их постоянно. Поскольку их срок службы до конца программы, нет необходимости распоряжаться ими. В этом случае мы не утилизируем мусор, потому что это не мусор; это полезно. Объекты GDI, которые не кэшируются, должны, конечно же, быть удалены. Опять же, преследование стратегии кэширования не является поводом для участия в плохих практиках.

Ответ 3

Когда вы закончите создание объекта Graphics, вы должны избавиться от него, вызывая его метод Dispose. (Это правило справедливо для многих разных объектов GDI +.) Не держите его в течение дождливого дня, потому что это не будет действовать позже. Вы должны, должны, распоряжаться им, когда закончите с ним. Если вы этого не сделаете, это может привести к повреждению изображения, проблемам использования памяти или, что еще хуже, к международному вооруженному конфликту. Поэтому, пожалуйста, утилизируйте все объекты Graphics правильно.

Если вы создаете объект Graphics внутри события, вам действительно нужно избавиться от него, прежде чем выйти из этого обработчика событий. Нет гарантии, что объект Graphics будет по-прежнему действителен в более позднем случае. Кроме того, легко воссоздать еще один графический объект в любое время.

Получено отсюда http://msdn.microsoft.com/en-us/library/orm-9780596518431-01-18.aspx

Ответ 4

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

Как правило, всякий раз, когда я создаю кисть, я делаю это в инструкции using. Это автоматически вызывает удаление кисти, не беспокоясь об этом. В качестве дополнительного бонуса, поскольку вы создаете кисть внутри инструкции, вы знаете, что она не является предопределенной кистью. Каждый раз, когда вы создаете и используете не предопределенную кисть, оберните блок при использовании, и вам не придется об этом беспокоиться. На самом деле вам даже не нужно явно вызывать Dispose, поскольку блок будет делать это даже в случае исключения.

Ответ 5

Короткий ответ:.. если вы его создадите, делегируйте ответственность за очистку или очистку объектов. Вы можете создать "утечки" ресурсов GDI, разрешив вещи в сборщике мусора. Они могут быть в конечном счете очищены, но они не делают никакого хорошего повешения там. т.е. если вы не вызываете "закрыть" или "Утилизировать" в открытых файлах, файл остается заблокированным до тех пор, пока GC "не приблизится к нему"

Ответ 6

Я мог ошибаться, но я думаю, вы можете предположить, что срок службы (и удаление) предопределенных кистей и ручек не является ответственностью вашего приложения и будет обрабатываться системой.

Вкратце: не вызывайте Dispose на предопределенные вещи.:)

Ответ 7

Единственное, что приходит в голову, - это не использовать в качестве параметров методы для использования системных ручек/кистей.

Ответ 8

Просто для полноты, используя Reflector, я вижу, что классы System.Drawing.Pen и System.Drawing.SolidBrush имеют личное поле с именем "неизменяемым".

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