Аллокатор памяти
Allocator отвечает за управление выделением памяти для приложения. Например, выделение оперативной памяти требуется при создании новой ноды.
По умолчанию стандартная системная функция malloc динамически выделяет память в куче. Однако использование стандартного аллокатора может привести к снижению производительности: для каждого выделения требуется дополнительный объем памяти. Другими словами, операционная система хранит данные о распределении памяти, и это может занять большой объем оперативной памяти. Кроме того, стандартный системный аллокатор предоставляет неточную информацию о статистике потребления памяти.
Вот почему UNIGINE в дополнение к стандартной системе malloc предоставляет пользовательский аллокатор. Он выделяет память в пулы, что ускоряет и повышает эффективность процесса выделения памяти. Кроме того, он позволяет собирать статистику о потреблении памяти, включая информацию об общем количестве выделений и количестве выделений на кадр.
Пулы памяти#
Пользовательский аллокатор UNIGINE предоставляет два основных пула памяти для распределения: статический и динамический.
- Статический пул выделяется только один раз при запуске двигателя и не может быть изменен.
- Динамический пул динамически увеличивается и вступает в игру, когда память, выделенная в статическом пуле, заполнена.
Существуют также дополнительные пулы экземпляров, в которых хранятся все ресурсы, определенные разработчиками. Как правило, это те ресурсы, которые требуются регулярно. Они работают так же, как и динамические пулы, но у пулов экземпляров нет ограничений по размеру.
Статический пул#
Статические пулы необходимы для оптимизации потребления памяти. Другими словами, при использовании статических пулов аллокации практически не требуют дополнительной памяти. Кроме того, это оптимизирует сами аллокации, ускоряя их.
Настройка статических пулов#
Статические пулы ограничены значениями размера, которые вы должны указать заранее. Для этого вам необходимо знать объем требуемой памяти и ее расположение. Проще говоря, вам нужно знать, какой объем памяти каждого типа (16, 32, 48 байт и т.д.) следует выделить. Например, на рисунке ниже показаны четыре статических пула, которые содержат аллокации объемом 16, 32, 48 и 64 байта:
Статические пулы должны настраиваться под конкретное оборудование, соответствующее минимальным спецификациям. Настройки статического пула хранятся в файле конфигурации .boot.
В целом, процесс выглядит следующим образом:
- В своем проекте определите место, для которого требуется значительный объем памяти.
- Настройте свой проект так, чтобы он начинался с этого места.
- Запустите приложение с параметром командной строки -memory_statistics_enabled 1. Это позволит собирать статистику по памяти, необходимую для настройки пула.
Статистика собирается только в том случае, если ранее не были настроены статические пулы.
- В консоли запустите консольную команду memory_optimize_static_pools, чтобы обновить и оптимизировать статические пулы.
- Сразу после этого запустите консольную команду boot_config_save, чтобы сохранить настройки статических пулов в файл конфигурации .bootдля использования при следующем запуске приложения.
- Перезапустите приложение, чтобы использовать обновленные конфигурации статического пула.
Динамический пул#
Динамические пулы также могут оптимизировать производительность, но они не могут оптимизировать потребление памяти. Однако они ограничены только объемом оперативной памяти, что является преимуществом. Кроме того, динамические пулы более гибкие, поскольку могут как расширяться, так и уменьшаться по мере необходимости.
Настройка динамических пулов#
Каждый динамический пул хранит аллокации определенного типа - 16, 32, 48 байт и т.д. Таким образом, вы всегда можете проверить, сколько памяти каждого типа выделено в динамических пулах. Эти значения всегда кратны 16. Например, на рисунке ниже представлено 16 пулов разных размеров:
Чтобы настроить динамические пулы, вы можете использовать консольную команду memory_dynamic_pool. Она определяет количество динамических пулов, указывая максимальный размер выделений. По умолчанию этот размер равен 256 байтам, что означает, что существует 16 пулов, содержащих выделения размером от 16 до 256 байт.
Анализ статистики пулов#
Чтобы получить информацию обо всех выделенных статических и динамических пулах памяти, используйте консольную команду memory_info.
Он отображает статистику по небольшим выделениям в виде таблицы, где каждая строка соответствует одному пулу памяти.
Распределение статических пулов |
|
Распределение динамических пулов |
|
Общий объем аллокаций |
Значения в таблице предоставляют статистику по всем распределениям памяти, которые произошли во всех пулах |
Распределение видеопамяти#
В дополнение к пользовательскому аллокатору оперативной памяти UNIGINE предоставляет возможность управления распределением видеопамяти с помощью пулов памяти.
Существует как минимум две причины для выделения видеопамяти:
- Минимальный объем памяти, который может быть выделен по умолчанию, составляет 64 Кб. Чтобы избежать выделения такого большого объема памяти для графических ресурсов значительно меньшего размера (например, текстур, для которых требуется гораздо меньше 64 Кб), нам необходимо использовать пулы памяти.
- Процесс выделения происходит крайне медленно, поэтому нам приходится выделять видеопамять заранее, а затем распределять ее по мере необходимости.
Настройка пулов#
Существуют консольные команды, которые позволяют настраивать пулы для выделения видеопамяти:
Файл конфигурации: | |
---|---|
Описание:
| |
Файл конфигурации: | |
Описание:
| |
Файл конфигурации: | |
Описание:
|
При настройке размеров блока необходимо найти баланс между скачками, производительностью и потреблением памяти. Чем больше размер блока, тем стабильнее частота кадров и производительность, но тем больше потребление памяти. Поэтому мы рекомендуем выполнить проверку для точной настройки значений.
Анализ статистики пулов#
Чтобы получить информацию обо всех выделенных пулах видеопамяти, используйте консольную команду video_memory_info. Она предоставит вам следующую информацию:
Heap Default | Значения в таблице отображают статистику по куче по умолчанию, включая текущее потребление видеопамяти, объем выделенной видеопамяти, количество выделений в пуле и так далее. |
Heap Upload | Значения в таблице отображают статистику по куче, используемой для загрузки. |
Heap Readback | Значения в таблице отображают статистику по куче, используемой для обратного считывания. |
Для получения более подробной информации, пожалуйста, обратитесь к этой статье.
Профилирование аллокаций#
UNIGINE предоставляет статистические данные об использовании оперативной и видеопамяти и профилировании аллокаций. Чтобы получить доступ к этой информации, запустите Generic Performance Profiler и посмотрите на следующие значения:
Статистика распределения оперативной памяти#
CPU ram free | Объем доступной в данный момент памяти. |
CPU ram usage physics | Текущий размер рабочего набора. Рабочий набор - это набор страниц памяти, которые в данный момент отображаются в физической оперативной памяти (смотрите в источнике). |
CPU ram usage committed | Общий объем частной памяти, выделенный менеджером памяти для запущенного процесса (смотрите в источнике). |
CPU ram malloc | Объем памяти, выделяемый пользовательским аллокатором UNIGINE. |
CPU ram static pool | Объем памяти, выделяемый в статических пулах. |
CPU ram dynamic pool | Объем памяти, выделяемый в динамических пулах. Доступно только в Windows. |
CPU ram instance pool | Объем памяти, выделяемый в пулах экземпляров. |
Frame Allocations | Количество аллокаций, выполненных для каждого кадра. |
Live Allocations | Текущее/максимальное количество аллокаций, выполненных во время выполнения (пиковое потребление). |
Статистика распределения видеопамяти#
GPU vram free | Объем доступной в данный момент видеопамяти. |
GPU vram usage | Объем видеопамяти, используемый графическим процессором. Это значение задается графическим драйвером. |
GPU ram usage | Объем оперативной памяти, используемый графическим процессором. Это значение задается графическим драйвером. |
GPU alloc | Количество аллокаций, выполненных движком на графическом процессоре. |
GPU Frame Allocations | Количество выделяемой видеопамяти для каждого кадра. |
GPU Live Allocations | Текущее/максимальное количество аллокаций, выполненных во время выполнения (пиковое потребление). |
GPU Allocator small pool size | Максимальный размер пула видеопамяти. |
GPU Allocator small usage | Фактическое использование пула видеопамяти. |
Существует также отдельный блок статистики, который отслеживает распределение памяти для Skinned Mesh и декалей.
GPU Allocator skinned | Объем видеопамяти, выделенный для Skinned Mesh. |
GPU Allocator decals | Объем видеопамяти, выделенный для декалей. |
Память выделяется независимо для каждого Skinned Mesh в сцене. Видеопамять для Skinned Mesh выделяется отдельными блоками в отдельном пуле. UNIGINE позволяет настраивать размер блоков с помощью консольной команды skinned_mesh_pool_chunk_size. По умолчанию этот размер составляет 64 Мб.
То же самое касается и декалей. Чтобы настроить размер блока для декалей, используйте консольную команду decal_pool_chunk_size.