Подтвердить что ты не робот

Почему бы не выделять и освобождать память часто в играх на С++?

Я недавно перешел на С++ для игрового программирования. У меня есть большой опыт работы с управлением памятью и проблемами с мусором в С#, но не с С++.

В прошлом я слышал некоторые неясные советы, чтобы избежать распределения и освобождения во время игры (т.е. new и delete) и предварительно выделить все, что вам может понадобиться. Но это намного сложнее и сложнее, чем просто выделять и освобождать игровые объекты по мере необходимости во время игры (врагов, частиц и т.д.).

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

Итак, мой вопрос: в мире ПК с гигабайтами памяти стоит ли головная боль настраивать продуманный пул памяти, предварительное выделение и т.д. для моих данных состояния игры? Или это просто какая-то неоспоримая традиция "лучшей практики", которая развивалась при максимизации ограниченных платформ, которые теперь повторяются как Евангелие?

Если мои 2 Мб игровых данных становятся фрагментированными и теперь распространяются на 4 МБ, я не могу представить, что это имело малейшее значение на ПК после 1990 года, но любопытно узнать, не хватает ли я чего-то:).

4b9b3361

Ответ 1

Основные причины, чтобы избежать вызова new, если это не необходимо в игровой среде, это

  • Динамическое распределение памяти действительно удивительно дорого.
  • Недостатки кэша вредны для производительности.

Динамическое распределение

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

Я могу сказать вам по опыту, что простая ошибка, связанная с распределением достаточно большого std::vector с нуля каждого кадра, вместо повторного использования предварительно выделенной памяти, может перетащить частоту кадров вниз в желоб.

Недостатки кэша

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

Мораль истории

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

Ответ 2

в мире ПК с гигабайтами памяти

И только несколько мегабайт для вашего процесса, если на этом ПК запущена нормальная ОС. (Но это не главная проблема здесь.)

Стоит ли головная боль настраивать продуманный пул памяти, предварительное выделение и т.д. для моих данных состояния игры.

Я не смею сказать, что "всегда предопределять все", потому что иногда это просто невозможно, а для менее часто используемых объектов это может не стоить усилий, но, безусловно, верно, что динамическое управление памятью в C и С++ являются ресурсоемкими и медленными. Итак, если вы визуализируете, например, 30 кадров в секунду на экране, то, возможно, избегайте выделения и де-выделения, а затем перераспределите буфер для объектов, которые будут отображаться во время каждого кадра/итерации.