Книга: Программирование мобильных устройств на платформе .NET Compact Framework

Производительность и управление памятью

Производительность и управление памятью

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

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

Частота выполнения сборки мусора напрямую зависит от того, насколько быстро ваш код расходует память приложения. Дефицит памяти в приложениях может быть обусловлен двумя факторами: 1) суммарным объемом поддерживаемого состояния приложения, включая всевозможные формы, глобальные объекты, пользовательские данные и любые другие объекты, содержащиеся внутри глобальных родительских объектов, и 2) временными объектами, которые создаются и разрушаются в процессе выполнения ваших алгоритмов. Если посмотреть на график изменения объема памяти, расходуемой приложением в процессе своего выполнения, то он будет иметь пилообразную форму. Высота зубьев этой пилы определяется тем, какой объем памяти вы оставляете для использования вашими алгоритмами, где имеется в виду память, не входящая в состав постоянно распределенной памяти приложения. Наклон же зубьев зависит от того, насколько эффективны процедуры распределения памяти для объектов, используемые в ваших алгоритмах. Чем более экономичны алгоритмы в отношении размещения новых объектов, тем более пологий наклон имеют зубья. В конечном счете, объем занимаемой приложением памяти начинает превышать некоторое пороговое значение, что приводит к запуску механизма сборки мусора, осуществляющего освобождение памяти от неиспользуемых объектов.

На рис. 12.1, 12.2, 12.3 и 12.4 проиллюстрированы четыре основных типа потребления памяти.

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

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


Рис. 12.1. Наихудший случай: чрезмерное потребление памяти состоянием приложения, неэкономичные алгоритмы

На рис. 12.2 представлен промежуточный в отношении производительности случай. Хотя этому варианту поведения системы, как и предыдущему, также свойственно неэкономное размещение объектов в памяти алгоритмами приложения, тем не менее, объем постоянно распределенной памяти в этом случае гораздо меньше. Это означает, что, несмотря на то, что наклон линии, отображающей процессы непрерывного размещения и уничтожения объектов, остается крутым, имеется гораздо больше свободного пространства, способного дольше хранить "мусор". Таким образом, необходимость в сборке мусора будет возникать гораздо реже, в результате чего производительность значительно улучшается по сравнению с предыдущим случаем.

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

На рис 12.4 представлен наиболее оптимальный вариант расходования памяти.


Рис. 12.2. Промежуточный случай: эффективно организованное состояние приложения, неэкономичные алгоритмы


Рис. 12.3. Промежуточный случай: чрезмерное потребление памяти состоянием приложения, экономичные алгоритмы


Рис. 12.4. Наиболее оптимальный случай: эффективное состояние приложения, и экономичные алгоритмы

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

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

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

Оглавление книги


Генерация: 1.129. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз