Насколько важно избавляться от шрифта?

Я знаю, что наилучшей практикой является вызов Dispose на любом объекте, который реализует IDisposable, особенно объекты, которые обертывают конечные ресурсы, такие как дескрипторы файлов, сокеты, дескрипторы GDI и т.д.

Но я столкнулся с тем случаем, когда у меня есть объект, у которого есть Font, и мне нужно было бы вскрыть IDisposable через несколько слоев объектов и просмотреть множество обычаев, чтобы я всегда получал шрифт, И мне интересно, стоит ли этого сложности.

Было бы одно, если Font завернул HFONT, потому что ресурсы GDI являются системно-глобальными. Но Font не переносит дескриптор GDI; он GDI +, который является полностью отдельной системой, и, насколько я понимаю, является локальным процессом, а не системно-глобальным, как GDI. И в отличие от Image, Font никогда не держит ресурсы файловой системы (что я знаю, во всяком случае).

Итак, мой вопрос: какова реальная стоимость предоставления Шрифту сбора мусора?

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

Есть ли издержки, о которых я не знаю, позволяя Font получить GCed?

Ответ 1

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

Ответ 2

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

Но для одного или двух экземпляров Font это не повредит вам.

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

Ответ 3

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

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

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

Что касается шрифта, MSDN говорит:

Всегда вызывайте Dispose перед тем, как вы отпустите свою последнюю ссылку на Font. В противном случае ресурсы, которые он использует, не будут освобождены до тех пор, пока сборщик мусора не вызовет метод Finalize объекта Font.

Он не говорит, что такое ресурсы, но тот факт, что они явно указывают, что это должно быть сделано неявно, добавляет важность вызова Dispose.

Ответ 4

Насколько важно избавляться от чего-либо, действительно? ИМХО, когда вы начинаете задавать такие вопросы, похоже, что у вас проблемы с дизайном в вашем коде. Вы всегда должны распоряжаться вещами, которые вам больше не нужны, - это называется ответственным программированием.

Возможные решения вашей проблемы:

  • Не пропускайте объекты, такие как Fonts. Внедрить логику использования шрифтов в одном месте (один класс), добавить шрифт в качестве поля этого класса и реализовать IDisposable для этого класса.

  • Внедрить класс кеша шрифтов - вместо создания новых объектов Font с помощью оператора new по всему вашему коду, используйте этот класс, чтобы получить желаемый Font. Затем класс может иметь логику повторного использования существующих шрифтов, если это возможно. Или сохранить последние 10 шрифтов в памяти и избавиться от остальных. Внесите IDisposable для кеша, который будет вызываться один раз в жизненном цикле вашего приложения.

Ответ 5

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

ГК была построена, чтобы иметь собственный псевдо-разум. Правильно избавляясь от своих объектов, вы позволяете GC делать то, что он сделал.

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

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

Ответ 6

У меня есть хотя бы одно другое приложение, использующее среду выполнения .NET. Я продолжаю получать OutOfMemoryExceptions. Было бы неплохо заставить ваше приложение вести себя так, чтобы в других приложениях не возникали исключения, когда они не могли получить достаточное количество ресурсов.