Анализ объема физической памяти приложения с помощью Memory Profiler

ANTON KRUGLYAKOV / UNITYSenior Software Engineer
Mar 28, 2023|10 Мин
Анализ объема физической памяти приложения с помощью Memory Profiler
Эта веб-страница была переведена с помощью машинного перевода для вашего удобства. Мы не можем гарантировать точность или надежность переведенного контента. Если у вас есть вопросы о точности переведенного контента, обращайтесь к официальной английской версии веб-страницы.

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

Скоро мы выпустим Memory Profiler 1.1 (экспериментальная версия доступна уже сейчас), который содержит обновленные надписи и описания, объясняющие, как работает память и как рассчитывается объем памяти приложения.

Так как вопрос об объеме памяти продолжает оставаться актуальным в наших беседах с разработчиками, я хочу ответить на ваши часто задаваемые вопросы - в частности, затронуть эти три темы:

  • Что такое резидентная память
  • Как рассчитывается объем памяти приложения
  • Как проанализировать объем занимаемой памяти
Резидентная память, определенная

Давайте разберемся с распределением памяти в Unity. Когда движок выделяет память, он сначала резервирует несколько страниц памяти в виртуальном адресном пространстве, которые могут соответствовать запрашиваемому объему. Страницы - это наименьшие единицы управления памятью. Виртуальное адресное пространство и физическое хранилище организованы в виде страниц, размер которых зависит от используемой платформы. Например, на компьютерах x86 размер страницы составляет 4 КБ.

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

Графическое изображение зарезервированных страниц | Memory Profiler deep dive

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

Графическое изображение зафиксированных страниц | Memory Profiler deep dive

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

Графическое изображение подмененных страниц | Memory Profiler deep dive

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

Как рассчитывается объем памяти приложения

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

В целом, состояние памяти вашего приложения можно описать с помощью этой диаграммы:

Диаграмма состояния памяти приложения

Вкратце, вот как рассчитывается объем занимаемой памяти:

Площадь физической памяти = резидентная память приложения + страницы сжатой памяти приложения
Анализ объема памяти

В Memory Profiler 1.1 представления Summary, Unity Objects и All Of Memory не только показывают объем выделенной памяти, но и предоставляют информацию о резидентной памяти. Однако эта информация будет показана только в том случае, если снимок Memory Profiler сделан в Unity 2023.1 или более новой версии. При использовании более старых снимков вы по-прежнему будете видеть обновленный пользовательский интерфейс и представления о сбоях, но без информации о памяти Resident.

Сводный вид Memory Profiler 1.1 в редакторе Unity Editor

ПредставлениеSummary дает общий обзор и основные метрики: Всего резидентов на устройстве. Если ваше приложение должно работать на платформе с ограниченным объемом памяти, Total Resident on Device очень важен для просмотра предупреждений о низком уровне памяти и вытеснений из памяти. Как правило, не следует превышать 70 % от общего объема физической памяти, доступной на устройстве.

Для детального анализа можно использовать представления Unity Objects иAll of Memory. Вам нужно выбрать Resident on Device или Allocated and Resident on Device из выпадающего меню и отсортировать по размеру Resident, чтобы увидеть объекты, которые вносят наибольший вклад в общий объем используемой физической памяти.

Все виды памяти для Memory Profiler 1.1 в редакторе Unity Editor

Анализируя использование резидентной памяти, помните:

  • Управляемая память будет преобладать над резидентной. Mono Heap и Boehm Garbage Collector регулярно обращаются к объектам и делают их резидентными.
  • Графическая память (оценочная) показана как оценочная. На большинстве платформ у нас нет доступа к информации о точном местонахождении графических ресурсов, поэтому мы оцениваем размер на основе доступной информации, такой как ширина, высота, глубина, формат пикселей и так далее. Это также означает, что у нас нет информации о резидентном статусе графических ресурсов. По соображениям удобства все графические объекты отображаются только в режиме просмотра Allocated.
  • Неотслеживаемая память - это вся память, о которой ОС сообщает как о выделенной приложением, но в которой отсутствует достоверная информация об источнике выделения. Это могут быть нативные плагины, библиотеки ОС, стеки потоков и т. д. На некоторых платформах мы предоставляем дополнительные сведения о том, кто мог выделить эту память в разбивке по группам.

При анализе нативной памяти, которая содержит все неуправляемые выделения Unity, используемые объектами, вы увидите элемент Reserved memory. Это память, выделенная диспетчером памяти Unity, но не используемая ни одним объектом Unity во время захвата. Вот несколько полезных сведений:

  • Зарезервированная память может быть резидентной, а это значит, что в ней мог находиться объект, который недавно был удален.
  • Вы можете получить дополнительную информацию о разбивке зарезервированной памяти, перейдя в настройки Memory Profiler и включив флажок "Показывать разбивку зарезервированной памяти". По умолчанию эта опция отключена, так как разбивка Reserved не всегда содержит достаточно полезной информации и требует глубокого понимания работы Unity Memory Manager.
  • Подробнее о диспетчере памяти Unity и стратегиях распределения можно узнать в документации по настройке распределителей.

На некоторых платформах мы показываем дополнительные группы для конкретной платформы, если они имеют значительный размер, например Android Runtime на Android. Вот несколько заметок об Android Runtime:

  • В некоторых версиях Android Runtime, как правило, предварительно выделяет значительный объем памяти, но никогда не использует его. В этом случае выделенная память не увеличивает объем памяти приложения, и нужно учитывать только ее резидентную часть.
  • Если резидентная часть Android Runtime занимает значительный объем памяти приложения, используйте профилировщик Android Studio для анализа выделений, выполняемых на Java.
  • Хотя в Android по умолчанию нет страничного файла или сжатия памяти, ядро Linux позволяет приложениям перераспределять и выделять больше памяти, чем физически доступно.
  • При съемке убедитесь, что вы понимаете, какое устройство используете. Некоторые производители поставляют для ядра Android Linux средства сжатия памяти (zRAM) или подкачки страниц.
Заключение

Мы надеемся, что этот обзор того, чего стоит ожидать от Memory Profiler 1.1(экспериментальная версия доступна уже сейчас), и исследование различных тем, связанных с отпечатками памяти, были полезны.

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

Поделитесь с нами своими отзывами на форумах. Следите за новыми техническими блогами от других разработчиков Unity в рамках продолжающейся серии Tech from the Trenches.