Шаблони розподілу пам'яті, що використовуються при розробці гри


20

Я займався дослідженнями створення власних методів розподілу (які підтримуватимуть такі речі, як пул пам’яті та профілювання), проте, продовжуючи дослідження, я шукав, як це було зроблено в розробці ігор.

Яку техніку розподілу пам’яті я можу використовувати і чому це хороша техніка?


1
вам справді потрібно? це просто одна із найскладніших речей, яку команда може реалізувати коли-небудь, якщо вона зможе її реалізувати.
Ali1S232

4
Це поле для мене цікавить, тому я хотів би дізнатися про нього та втілити його в життя
чадб

Треба сказати, що тема дуже цікава ... Є випадки, коли це може означати багато, але на середній комп'ютерній грі я б швидше
переймався

Ви досліджували вихідний код для сучасної стандартної бібліотеки malloc та вільної чи нової та видалення? Я запитую, бо, здається, це могло б стати дуже корисною базою, на основі якої можна порівняти будь-які альтернативні стратегії розподілу з алгоритмічно чи практично. Здається, це також дасть реальне уявлення про те, що ви будете отримувати.
Луї Лангхольц

Відповіді:


25

Архітектура ігрового двигуна має деяку інформацію щодо цієї теми. Основи полягають у тому, що вам потрібно зробити якийсь аналіз, щоб зрозуміти, які ваші вимоги до пам'яті на рівень / кадр / тощо. подібні, але є кілька зразків, про які автор згадує, побачивши кілька разів:

  • Алокатори на основі стеків: Вони виділяють один раз великий сегмент пам'яті, а потім виділяють покажчики всередині цього блоку пам'яті у відповідь на запити з інших місць гри. Це корисно, щоб уникнути контекстних комутаторів, необхідних для розподілу пам'яті, а також тому, що ви можете використовувати власні методи для забезпечення суміжності або конкретного вирівнювання для операцій SIMD. Деякі двигуни також використовують двосхилий стек, де один вид ресурсу завантажується зверху, а другий завантажується знизу. Можливо, LSR (Load and Stay Resident - така річ, яка знадобиться протягом усієї вашої гри) зверху, а дані за рівнем знизу.
  • Однокадрова пам'ять або двопаперова буферна пам'ять: Пам'ять для операцій, що відбуваються протягом одного або двох циклів кадру. Це корисно, тому що замість того, щоб виділяти / розміщувати кожен кадр, ви можете просто видути дані останнього кадру, скинувши вказівник, який ви використовуєте, щоб відслідковувати пам'ять до початку блоку.
  • Об'єктні пули: Блок пам'яті для багатьох об'єктів одного розміру, таких як частинки, вороги, снаряди. Вони корисні, оскільки ви можете легко досягти суміжності, знайшовши перший невикористаний сегмент у своєму пулі. Вони також спрощують ітерацію, оскільки кожен об'єкт знаходиться у відомій зміщенні від останнього.

Найбільше, на що автор зазначає звернути увагу, - це фрагментація пам'яті. Це менше проблеми, якщо ви розробляєте, наприклад, для ПК, де у вас є якась резервна копія підключення до пам'яті, на яку ви можете розраховувати, але у фіксованому контексті пам'яті, як консолі, є ризик "не з пам'яті" коли ви намагаєтеся виділити великий об’єкт, оскільки ваша пам'ять фрагментована таким чином, що доступні лише невеликі суміжні блоки. З цією метою він рекомендує, щоб алокатор на основі стека, як зазначено вище, також включав метод періодичної дефрагментації його вмісту.

Для отримання додаткової інформації про власне код, який я присвячений цьому, я настійно рекомендую статтю Крістіана Гірлінга "Ми не з пам’яті?" , яка охоплює методи для користувацьких алокаторів, здебільшого з точки зору аналізу моделей використання пам'яті, але це також застосовно до розробки спеціального рішення для управління пам'яттю.


1

З того, що я бачив (але не зробив), кожна гра має тенденцію або успадковувати механізми розподілу з фреймворку, від ігрового двигуна, з попередньої версії (2010 -> 2011) або отримує набір нових, написаних спеціально для його структура (або коли структури даних багаторазово використовуються і мають фіксований розмір, або численних типів і змінних розмірів).

Також у нас в одному проекті були різні розподільники звукових файлів / компонентів, ніж для рівнів та інших ігрових об'єктів. В інших проектах аллокатори успадковуються від зовнішніх бібліотек лише за компонентами, якими керує цей lib.

Оптимізація дійсно залежить від ваших потреб. Але зазвичай розподіл проводиться до виходу на ігрову сцену, після чого пам'ять використовується повторно. Деякі ігри можуть уникнути, не даючи спеціальних розподільників. Але для екшн-ігор, де процесор, пам'ять і ресурси даних передбачені бюджетом, ви не можете дозволити собі втратити час на обробку великих розмірів, ви не можете витрачати пам'ять на фрагментацію та інші проблеми.

Щодо прикладів, вам слід просто почати, ознайомившись з ігровим двигуном OGRE 3D, у нього є кілька варіантів налаштування розподільників пам'яті.


0

Помилка, яка часто робиться, полягає в тому, щоб написати свої власні алокатори, щоб ви мали більше контролю над тим, скільки пам’яті використовується кожною системою та мати більшу видимість того, що відбувається. Набагато кращий спосіб досягти цього - використовувати профайлер пам'яті. Профілів пам’яті безліч , один із прикладів - мій профілер MemPro . Це абсолютно неінвазивний спосіб відстежувати все використання пам’яті, і ви можете автоматично розбивати її на підсистеми за допомогою фільтрів підстановок для виклику. В ідеалі найкраще, щоб розподіл пам’яті та відстеження пам’яті було повністю розділеним, вони мають абсолютно різні вимоги.

Довільний поділ вашої пам’яті на пули часто може завдати шкоди, оскільки кожен пул матиме накладні витрати. Ви можете використовувати набагато більше пам’яті, ніж вам потрібно, фактично не усвідомлюючи цього. Щоб зменшити витрату, завжди краще збивати все разом, а потім слабкість ділиться всією системою.

Єдиними причинами використання спеціальних алокаторів є продуктивність процесора (головним чином для когерентності кешу) та обмеження фрагментації. Прекрасним прикладом цього є система частинок. Ви хочете, щоб усі частинки були суміжними в пам'яті, і ви не хочете перецьовувати основну пам'ять з великою кількістю короткочасних виділень. Ще один хороший приклад для розділення - це сценарій мови.

Якщо ви хочете прикладу заміни малика загального призначення, ви можете подивитися на мій розподільник VMem . Він був використаний у ряді ігор AAA, що поставляються. У ньому є методи, які обмежують фрагментацію і знижують слід пам'яті, що є критичним для консольних ігор. Це також дуже швидко в умовах високої вмісту ниток. Мій веб-сайт має велику документацію щодо цих методів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.