Должен ли я создавать новые ручки / кисти для каждого запроса Paint или сохранять их на протяжении всего жизненного цикла приложения? - PullRequest
16 голосов
/ 20 августа 2010

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

using(var pen = new Pen(this.ForeColor))
{
    // Paint for this object.
}

Я прочитал противоречивые ответы, что это должно быть сделано для приложения, которое постоянно рисует одну и ту же вещь (возможно, просто изменяет размер, перемещает и т. Д.). Должен ли я хранить Pen/Brush с объектом, а затем утилизировать их все, когда приложение удаляется, или они достаточно эффективны, чтобы их можно было создавать / удалять для каждого вызова рисования (помня, что это симпатичная графика интенсивное применение).

РЕДАКТИРОВАТЬ : уже есть два ответа с противоречивыми ответами, и я не уверен, что смогу переключиться. У кого-нибудь есть статистика по различиям?

Ответы [ 5 ]

9 голосов
/ 20 августа 2010

Конечно, вы можете использовать классы Pens и Brushes, которые предоставляют вам объекты, которые уже созданы средой выполнения.

Например, если вам нужен один из стандартных цветов Ручки , вы можете сделать это:

var pen = Pens.Red;

Аналогично, вы можете сделать то же самое с Кистями , если вы просто хотите использовать стандартные однотонные кисти:

var brush = Brushes.Red

Используя их, вам не нужно беспокоиться о том, чтобы очистить их, утилизировать или иным образом.

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

EDIT:

Для создания и утилизации массива из 100 000 новых перьев на моем древнем старом компьютере с XP потребовалось примерно полсекунды, запустив тестовое приложение в режиме отладки.

Это соответствует примерно 5 микросекундам на ручку . Только вы можете решить, достаточно ли это для вас. Я бы рискнул предположить, что это время может быть в значительной степени незначительным в отношении остальных ваших операций.

3 голосов
/ 20 августа 2010

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

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

Если вы используете относительно немного разных цветов, но многие объекты используют каждый цвет, вы можете не захотеть, чтобы каждый объект держался за свое перо. Создайте некоторый класс кэша, который хранит Dictionary<Color,Pen> и раздает их через PenCache.GetPen(ForeColor). Как и при использовании Pens.Black, теперь вы можете забыть об их утилизации. Проблема возникает, если вы кратко используете цвет, тогда он вам больше не нужен. Ручка была кэширована, так что вы застряли с ней в памяти навсегда. Вместо этого вы можете оставить Dictionary<Color,WeakReference<Pen>>, что позволит в конечном итоге собирать кэшированные ручки, если они больше не нужны.

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

2 голосов
/ 20 августа 2010

Повторное использование одних и тех же Pen и Brush в операциях, которые требуют многократного выполнения, будет намного быстрее, чем их удаление каждый раз с using.

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

0 голосов
/ 08 мая 2018

Хорошо, это старый вопрос, для некоторых он, вероятно, новый и имеет простое и интуитивно понятное решение с подробным объяснением.

«Должен ли я держаться, чтобы рисовать ресурсы, такие как ручки и кисти, дольше, чем требуется для предварительной операции по рисованию», вопрос перефразирован?Ответ - нет, вы не должны в этом контексте;но почему, что это значит?

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

Да, создайте перья, создайте кисти и т. Д. Для рисования и выполните myPen.dispose (), и сразу же после этого освобождайте все ссылки на объект для удаленного объекта, устанавливая для этого дерева объектов значение null, например (myPen = null;) это позволяет сборщику мусора освободить неуправляемую память, которая хранится в этих объектах, не дожидаясь вызова объекта finalize ().Смотрите: Сборка мусора для получения дополнительной информации о том, как сборка мусора работает в C #.

Создание слишком большого количества этих объектов класса IDisposable и не освобождение этих объектов после завершения « Использование » может привести к серьезным последствиям для работы вашей программы, таким как возможные исключения стека и кучи памяти, вызывающиеповышенная загрузка ЦП за счет необходимости сортировки ненужных количеств объектов, которые могут привести к снижению производительности и даже к аварийному завершению во время выполнения, если его не проверять.См. Stack and Heap для получения дополнительной информации.

Мораль истории высвобождает ресурсы, которые вам больше не нужны;если вам необходимо сохранить ресурсы, протестируйте на стенде потенциальное влияние на производительность, когда вы «держитесь за ресурсы», надеясь избежать негативных последствий.

Практическое правило. В лучшем случае убедитесь, что все ресурсы высвобождаются при выходе из вашего "рисовать событие "рутина".Предпочтительно, когда каждый из ваших методов события рисования заканчивается так же, должны любые ресурсы, неявно созданные этим методом.Штраф, любые ссылки на объекты *, передаваемые этим методам, таким как ручки, кисти и т. Д., Будут удерживаться до тех пор, пока не будет вызван финализатор базового объекта, что дольше, чем необходимо, и может рассматриваться как утечка памяти в общих терминах определения.* Передача слишком большого количества ссылок равняется неиспользуемой памяти в течение более длительного периода, чем то, что, вероятно, ожидается или предполагается.

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

Счастливая картина!

0 голосов
/ 20 августа 2010

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

...