Книга: Программирование мобильных устройств на платформе .NET Compact Framework
Старайтесь избегать распределения памяти для объектов при выполнении повторяющихся или непрерывно продолжающихся операций рисования
Старайтесь избегать распределения памяти для объектов при выполнении повторяющихся или непрерывно продолжающихся операций рисования
Выполнение лишних операций размещения и уничтожения объектов в памяти является одной из наиболее распространенных причин ухудшения производительности графического кода. Графический код часто выполняется внутри циклов или многократно вызывается. Кроме того, поскольку графические объекты используют значительные объемы памяти, а также системные ресурсы, с их обслуживанием связаны сравнительно большие накладные расходы. Если ваше мобильное приложение распределяет и освобождает память всякий раз, когда необходимо визуализировать изображения, то вы неминуемо столкнетесь с проблемами нехватки памяти, что обусловит необходимость частого выполнения операций по сборке мусора, замедляющих работу приложения. В связи с этим необходимо предельно внимательно анализировать любые участки кода, требующие распределения памяти для объектов в процессе визуализации графики. Особенно это касается объектов, связанных с графическими ресурсами, но остается справедливым и по отношению к объектам другой природы (например, коллекциям, массивам, строкам), которые могут фигурировать в таком коде.
В частности, вы должны анализировать с этой точки зрения распределение памяти для следующих объектов.
? Объекты Bitmap. Часто возникают ситуации, в которых в качестве временного хранилища для изображения или части изображения, создаваемых вашим приложением, удобно использовать объект Bitmap. Если вашему приложению требуется пространство для рисования, то в этом нет ничего необычного; единственное, чего следует избегать — так это создания и уничтожения многих битовых изображений в циклах рисования. Обычно гораздо лучше иметь одно рабочее пространство, многократно используемое в качестве общего ресурса, чем нести дополнительные затраты, связанные с непрерывным созданием и уничтожением временных изображений. Размер такой временной памяти должен быть равен размеру наибольшего временного изображения, которое может понадобиться вашим процедурам (но не более того). Если временную память необходимо очищать, прежде чем использовать ее для рисования, то это можно сделать легко и быстро при помощи вызова Graphics.Clear(). Кроме того, как продемонстрировано в приведенном выше примере кода, часто используемые растровые изображения имеет смысл загружать и кэшировать в памяти. Следите за тем, чтобы в каждый момент времени загружался только один экземпляр растрового изображения. Загрузка нескольких экземпляров идентичных изображений приведет к напрасному расходованию больших объемов памяти.
? Объекты Graphics. Если требуется постоянно перерисовывать растровое изображение, как это, например, приходится делать при перерисовке кадров игрового поля, то, вероятно, наряду с целевым экранным изображением целесообразно кэшировать также объекты Graphics внеэкранных изображений. Поступая таким образом, вы избавитесь от необходимости непрерывного размещения этих объектов в памяти и их удаления. Не распределяйте в циклах рисования память для объектов Graphics растровых изображений или форм более одного раза; в идеальном случае следует вообще избегать размещения и удаления таких объектов внутри циклов. To же самое касается и любых других битовых карт, в которых вы должны выполнять рисование; кэшируйте их объекты Graphics, а не создавайте их каждый раз заново. Учтите, что объекты Graphics нужны только для тех битовых карт, которые вы используете для создания изображений; если битовая карта используется лишь в качестве источника информации об изображении, то объект Graphics для нее вам вообще не нужен.
? Объекты Font, Brush, Pen, ImageAttribute. Распространенной ошибкой разработчиков, причины которой вполне объяснимы, является их чрезмерное увлечение управлением временем жизни ресурсов на микроуровне, не сопровождающееся глубоким анализом их использования на макроуровне. В процессе создания графического изображения вам может потребоваться пройти, скажем, через 30 отдельных этапов, в ходе которых рисуются линии, закрашиваются эллипсы, создается текст и копируются битовые образы. Выполнение каждой из этих операций требует использования некоторой комбинации перьев, кистей, шрифтов, то есть объектов Pen, Brush, Font, а если в дело включаются еще и маски прозрачности, то и объектов ImageAttribute. В случае мобильных устройств ситуация усугубляется тем, что в .NET Compact Framework, в отличие от .NET Framework, статические версии базовых кистей и перьев не предусмотрены. Так, в версии NET Framework, ориентированной на настольные компьютеры, существуют, например, объекты System.Drawing.Pens.Blue и System.Drawing.Brushes.DarkOrange, но в NET Compact Framework эти объекты приходится распределять. Решение этой проблемы заключается в создании собственного глобального набора объектов Pen и Brush, который вы будете использовать для нужд рисования во всем приложении. Вы должны тщательно просмотреть все циклы рисования в приложении, обращая особое внимание на случаи повторного создания идентичных ресурсов и избавляясь от подобной избыточности в коде. Если в вашем приложении непрерывно выполняются операции рисования, то такие объекты, как шрифты, перья, кисти и маски прозрачности, должны либо однажды распределяться в цикле рисования, либо глобально кэшироваться.
? Типы, которые преобразуются (или, как еще говорят, "'упаковываются") в объекты. Наиболее распространенным типом значений, используемым в графических кодах, является структура System.Drawing.Rectangle. Обычно работа с типами, соответствующими значениям, отличается высокой эффективностью, поскольку их можно размещать в стеке (а не в глобальном пуле свободной памяти, или куче, как объекты). В то же время, значения также могут рассматриваться как объекты и размещаться в массивах или коллекциях или передаваться всюду, где допускается использование объектного типа. Тщательно следите за тем, чтобы не происходило неявное постоянное распределение и освобождение памяти, обусловленное "упаковкой" значений в объекты и их обратной "распаковкой".
Заботясь о том, чтобы в графическом коде приложения не выполнялось непрерывное создание и уничтожение часто используемых объектов, вы не должны забывать о необходимости следить за использованием глобальной памяти своего мобильного приложения. Если в графических функциональных возможностях нуждаются лишь отдельные части приложения, то следует подумать об освобождении занимаемых ими ресурсов, как только приложение входит в состояние, в котором в течение некоторого времени графические ресурсы ему не будут нужны. Хорошей практикой проектирования считается использование конечного автомата и определение тех графических ресурсов, от которых при выходе приложения из определенных состояний можно освободиться.
- Четырехминутный практикум по работе с графикой в .NET Compact Framework
- Способы интеграции графики с кодом пользовательского интерфейса
- Где рисовать — на экране или вне экрана?
- Определите собственный процесс визуализации
- Отсрочка — зло, используйте предварительные вычисления
- Кэшируйте часто используемые ресурсы
- Старайтесь избегать распределения памяти для объектов при выполнении повторяющихся или непрерывно продолжающихся операций рисования
- Иерархия объектов в InterBase
- Имена объектов длиной 68 символов
- Создание объектов Collection
- 3.2.1.2. Начальное выделение памяти: malloc()
- 4. Свойства унарных операций
- 3. Свойства бинарных операций
- 4. Варианты операций соединения
- 3.3. Определение объектов защиты
- Неисправности оперативной памяти
- Как работает модуль оперативной памяти
- Описание типов модулей оперативной памяти
- Извлечение и установка модулей памяти