Виділення та звільнення величезної частини пам'яті при запуску "очищає пам'ять?"


18

Книга кодування ігор завершена, четверте видання , глава 5 ( Ініціалізація і завершення гри ), розділ Перевірка пам’яті містить цей цікавий зразок коду:

bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
    MEMORYSTATUSEX status; 
    GlobalMemoryStatusEx(&status);
    if (status.ullTotalPhys < physicalRAMNeeded) 
    {
        // you don’t have enough physical memory. Tell the player to go get a 
        // real computer and give this one to his mother. 
        GCC_ERROR("CheckMemory Failure: Not enough physical memory."); 
        return false;
    }
    // Check for enough free memory.
    if (status.ullAvailVirtual < virtualRAMNeeded) 
    {
        // you don’t have enough virtual memory available.
        // Tell the player to shut down the copy of Visual Studio running in the 
        // background, or whatever seems to be sucking the memory dry. 
        GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
        return false;
    }

    char *buff = GCC_NEW char[virtualRAMNeeded]; 
    if (buff)
    {
        delete[] buff;
    }
    else
    {
        // even though there is enough memory, it isn't available in one
        // block, which can be critical for games that manage their own memory 
        GCC_ERROR("CheckMemory Failure: Not enough contiguous memory."); 
        return false;
    }
}

Це викликає деякі питання.

Перша частина просто запитує ОС (Windows), скільки фізичної оперативної пам’яті доступно. Цікава частина - друга, яка виділяє величезний шматок пам'яті і звільняє її відразу:

char *buff = GCC_NEW char[virtualRAMNeeded]; 
if (buff)
{
    delete[] buff;
}

Автор далі пояснює:

... ця функція виділяє і негайно звільняє величезний блок пам'яті. Це призводить до того, що Windows прибирає сміття, що накопичилося в диспетчері пам’яті, і двічі перевіряє, що ви можете виділити суміжний блок настільки великі, скільки вам потрібно. Якщо дзвінок вдався, ви, по суті, запустили еквівалент машини Zamboni через пам'ять вашої системи, підготувавши його до гри, щоб потрапити на лід ...

Але я маю свої застереження з цього приводу.

"Очищення сміття, що накопичилося в диспетчері пам'яті?" Дійсно? Якщо гра тільки почалася, чи не повинно бути сміття?

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

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

Це справді хороша практика?


3
Більшість сучасних ОС не зроблять нічого, коли додаток виділяє велику область пам’яті, вони використовують оптимістичний розподіл і фактично нічого не роблять, поки ви не заповнить пам’ять, я не можу уявити, що це робить щось більше, ніж бути потенційно повільним
бездіяльності

Чи очищення довгої смуги землі в джунглях, вирізання радіо, навушників тощо від дерева призводить до посадки літаків і доставки припасів?
Дан Нілі

10
Ігрове кодування завершено містить багато дурниць, поєднаних з безліччю нерозуміючих-C ++ та C-що-виглядає-трохи-як-C ++ (також продемонстровано в цьому зразку, перевіряючи результат operator newдля nullptr), якщо ви дозволите мені сказати. Найкраще, що ви можете зробити з цією книгою - запалити ваш димар. Виділення та звільнення великого блоку пам'яті, звичайно , не «очищає» пам’ять.
Деймон

@Damon, я не перевірив, але я підозрюю, що вони принаймні перевантажили глобального newоператора, щоб повернути null замість того, щоб кидати bad_alloc. Якщо вони цього не зробили, то так, цей код ще більш безглуздий: P
гламперт

1
@glampert: Навіть якщо припустити, що це так, operator deleteпотрібно прийняти nullptrта ставитись до нього як до неоперативного. Будь-яка глобальна перевантаження, яка цього не робить, порушена. Що означає, що це безглуздо. Так само, як припускати, що виділення величезного блоку пам’яті та звільнення його «магічно» принесуть щось хороше. У кращому випадку це не принесе шкоди (швидше за все, оскільки сторінки навіть не торкаються ... інакше це може змінити деякі сторінки з вашого робочого набору, які вам потрібно буде перезавантажити пізніше).
Деймон

Відповіді:


12

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

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

Однак, примушування подібного диска до цього не є точно на 100% надійним:

  • У багатьох реалізаціях віртуальної пам’яті просто розподілення пам’яті насправді не викликає будь-яких змін; швидше, це відбувається лише тоді, коли ви вперше отримуєте доступ до кожної сторінки виділеної вами пам'яті. (Це, безумовно, справедливо для сучасних версій Linux, з увімкненою перезавантаженням пам'яті, як це за замовчуванням; я не знаю точно, як в різних версіях Windows обробляється це.)

    Таким чином, якщо ви дійсно хочете, щоб цей код "очистив пам'ять", ви, ймовірно, повинні додати memset()виклик або еквівалент, щоб насправді записати дані в кожну частину масиву (або принаймні до перших physicalRAMNeededбайтів), перш ніж випускати його.

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

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

    (Там є способи програми насправді говорять ОС , щоб зафіксувати частину свого простору пам'яті в оперативну пам'ять і запобігти його вивантажено, але вони , як правило , вимагають підвищених привілеїв. У будь-якому випадку, код розміщений чи не здається, використовуючи будь-які подібні методи.)

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


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

3
Я думаю, що важливо пам’ятати, що все це є припущеннями, які можуть спрацювати, не спрацюючи або здаючись, що працюють, але з абсолютно незв’язаних причин. Наскільки мені відомо, жодна з поведінки, зазначеної у цій відповіді, не зафіксована документально, і покладатися на них було б нерозумно. Оновлення ОС, зміна налаштувань, зміна компілятора або багато чого іншого можуть змусити цю роботу припинити роботу або навіть негативно вплинути на продуктивність.
Піжама Panda

26

Я не знаю, скільки років цьому запису, але я б сказав, що він досить старий. У сучасних Windows (XP та новіших версіях, але спеціально для 64-розрядної версії) я б сказав, що щось подібне мало мати негативний вплив на запуск вашої гри.

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

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

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

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

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

Я думаю, що це випадок "це спрацювало з якихось причин, я насправді не розумію, тому я щось видумав, щоб це пояснити".


10
Оперативна пам’ять не схожа на обертовий жорсткий диск, де наявність суміжних блоків у будь-якому випадку "краща", ніж ні. Це не правда. суміжний доступ до оперативної пам'яті - на порядок швидший, ніж випадковий доступ. Чіпи оперативної пам’яті розбиваються на розділи, для яких є певна кількість затримок для перемикання, і що ще важливіше, помилки кешу L1 та L2 різко вплинуть на вашу продуктивність, коли пам’ять буде розсіяна.
CaptainCodeman

@CaptainCodeman: Я маю визнати, що це виходить з моєї галузі знань, але в будь-якому випадку, як програміст Windows-програми, ви не маєте контролю над тим, чи є ваша пам'ять фізично суміжною чи ні. Прохання про величезний блок пам'яті не зміниться багато.
Піжама Panda

@CaptainCodeman насправді мають суміжний віртуальний блок, що знаходиться у суміжному блоці mod 2 ^ N в оперативній пам’яті, прискорить його завдяки розподілу лінії кешу
ratchet freak

8
@CaptainCodeman Так, послідовний доступ до DRAM швидший, але ми говоримо про віртуальне-> фізичне відображення, яке відбувається на сторінках 4 Кб (або більше), тож, чи це відображення є послідовним чи ні, не повинно мати великого впливу на пам'ять швидкості читання. Плюс попереднє завантаження кешу та подібні речі, що працюють у віртуальному адресному просторі, а не у фізичному.
Натан Рід

1
@NathanReed Досить справедливо, і дякую за роз’яснення. Я просто висловлював, що швидкість доступу до оперативної пам’яті не зовсім однакова в усьому просторі пам'яті, як було запропоновано.
КапітанКодеман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.