Як ігри C ++ поводяться з помилкою розподілу пам'яті?


23

Мені відомо кілька ігор, які написані на C ++, але не використовують винятки. Оскільки поводження з помилкою розподілу пам'яті в C ++, як правило, будується навколо std::bad_allocвинятку, як ці ігри впораються з таким збоєм?

Вони просто виходять з ладу, або є інший спосіб впоратися з помилкою, що не залишилася в пам'яті?


1
Зауважте, що є певні середовища / ОС, де розподіл претендує на успішність, але спроба використовувати пам'ять
вибиває

6
Якщо розподілу не вдасться під час гри, Quake 3 поверне вас до меню із повідомленням про помилку. Я вважаю, що це стає можливим за допомогою розподільника пулу Quake 3, який може просто скинути весь пул і безпечно повернутися до меню, якщо пул закінчується.
Дітріх Епп

16
Зазвичай, врізавшись.
користувач253751

1
Якщо винятки справді відключені, програма замість цього повинна викликати std::terminate, і все. Але тоді за тим же обмеженням виділення може повернути нульовий покажчик замість викидання винятку, і цей результат можна перевірити та обробляти окремо.
підкреслити_

2
У C ++ ви можете сказати ClassName variableName = new(nothrow) ClassName();( очевидно, замінюючи ім'я класу, назву змінної тощо ). Потім, якщо розподіл не вдасться, ви можете виявити його, сказавши, if(!variableName)що дозволяє обробляти помилку без блоку виключень спробувати. Точно так же, якщо пам'ять виділяється з використанням функції , як malloc(), calloc()і т.д., то відмови виділити можуть бути виявлені з використанням того ж if(!variableName)методу без необхідності Try-улов. Що стосується того, як ігри впораються з цими помилками, тож, в цей момент, вирішувати, чи виходить з ладу чи ні, вирішуватиме розробка ігор.
Спенсер Д

Відповіді:


63

Те саме, що і всі середні програми: їх немає. *

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

Питання подібне до наступного:

  • Як встановити гру, якщо жорсткий диск заповнений?
  • Як ви все ще ведете гру на високій кадрі в секунду на ПК нижче мінімальних характеристик?

Відповідь однакова: це проблеми користувачів. Гра не хвилює.


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


2
На попередньому виділенні пам'яті для протоколювання і т.п. в разі збою виділення пам'яті: stackoverflow.com/questions/7749066 / ...
bwDraco

23

Зазвичай подібного сценарію ніколи не буває.

По-перше, віртуальна пам’ять в сучасних операційних системах означає, що навряд чи це станеться у звичайній роботі; якщо у вас не виникла помилка при розподілі, гра буде виділяти пам'ять з віртуального адресного простору ОС, і ОС буде доглядати за тимчасовим підключенням і вимкненням.

Це все добре і добре, але це не стосується консолей чи старих ОС, тому по-друге, ігри навіть не роблять багато невеликих динамічних виділень, використовуючи стандартні бібліотечні розподільники. Замість того, що вони зроблять, - виділити великий пул пам'яті одноразово під час запуску та витягнути з цього пулу будь-які виділення часу виконання, які потрібні (наприклад, за допомогою нового місця розташування C ++ або написання власної системи управління пам'яттю на зверху).

Це також захищає від витоків пам’яті, оскільки замість того, щоб відстежувати та враховувати кожне невелике виділення, гра може просто викинути весь пул, щоб повернути пам'ять.

І по-третє, ігри завжди встановлюватимуть мінімальну специфікацію і бюджетують їх використання в пам'яті. Отже, якщо для гри призначено вимагати 1 Гб оперативної пам’яті, це означає, що поки споживання пам'яті ніколи не перевищує 1 ГБ, їй ніколи не потрібно турбуватися про втрату оперативної пам’яті.


3
"Натомість те, що вони будуть робити, - виділити великий пул пам'яті одноразово під час запуску, і витягнути з цього пула будь-які виділення часу виконання, які потрібні" - і що ви думаєте, що станеться, якщо пул заповнений?
користувач253751

@immibis - дивіться, будь ласка, третій пункт.
Максим Мінімус

2
@immibis Ви маєте на увазі ... що вони роблять, якщо басейн пустий? На відміну від системної пам'яті, розмір та використання пулу повністю під контролем програми. Тож пул не може стати порожнім, якщо у програмі немає помилки.
Девід Шварц

@DavidSchwartz Або, якщо ядро ​​не використовує перезавантаження пам'яті. Linux робить це. Навіть зняття нуля вашого пулу не допоможе, якщо стиснення файлів сторінки ввімкнено через zswap або zram.
Damian Yerrick

1
Схоже, це не відповідає на власне питання, але натомість заявляє щось подібне до "Цей корабель є непорушним, для чого нам знадобиться екстрена процедура?"
Ліліенталь

2

Ну, головним чином, так само, як ми це робили і до того, як існували винятки - стара "перевірка підходу до повернення вартості". Якщо розподільник не використовує винятки, він зазвичай повертається, nullколи розподіл не вдається. Добре написана гра перевірить це і вирішить ситуацію будь-яким безпечним способом. Іноді це означає припинення гри (наприклад std::terminate) або принаймні повернення до останнього відомого безпечного стану (наприклад, коли ви виділяєте з пулу, ви можете сміливо утилізувати весь пул, навіть коли він знаходиться в небезпечному стані).

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

Майте на увазі, більшість ігор просто розбиться. Це не настільки божевільно, як це звучить - зазвичай ви використовуєте деяку пам'ять як ціль, і переконайтеся, що ваша гра не досягає цього ліміту (наприклад, за допомогою обмеження кількості одиниць в грі RTS або обмеженням кількість ворогів у розділі FPS). Навіть якщо ви цього не зробите, у вас зазвичай не вистачає пам'яті в будь-якій досить сучасній системі - у вас не вистачає віртуального адресного простору (в 32-бітному додатку) або стека, наприклад. ОС вже робить вигляд, що у вас стільки пам’яті, скільки ви просите, - це одна з абстракцій, яку забезпечує віртуальна пам'ять. Справа в тому, що те, що у вас є 256 Мб фізичної оперативної пам’яті, не означає, що ваш додаток не може використовувати 4 ГБ пам’яті. Деякі ігри можуть не надто заперечувати, щоб усі їх дані не були "


1

Зробити виняток і вирішити робити те, що коли і виняток, це дві різні речі.

Вам потрібно мати складну логіку, щоб звільнити пам'ять, яка не потрібна вашій програмі. Гірше, якщо будь-яка інша запущена програма або бібліотека просочується пам'яттю, то ви не маєте на ній контролю

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


Якщо ігри, про які йдеться, буквально «не використовують винятки», як сказала ОП, вони не можуть їх зловити, підняти чи обробити. Якщо винятки вимкнено, і хтось кидає його, програма замість цього повинна зателефонувати std::terminate, і все. Але за таких умов розподіл може повернути нульовий покажчик замість того, щоб викидати виняток, і це можна обробляти окремо.
підкреслюйте_d
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.