Книга Game Coding Complete, четвертое издание , глава 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 через память вашей системы, готовя ее к тому, что ваша игра выйдет на лед ...
Но у меня есть оговорки на этот счет.
"Очистка мусора, накопившегося в диспетчере памяти?" В самом деле? Если игра только началась, разве не должно быть мусора?
"Убедитесь, что вы можете выделить непрерывный блок?" В очень конкретном случае, когда вы собираетесь управлять памятью самостоятельно, это имело бы какой-то смысл, но, тем не менее, если вы действительно выделяете много памяти прямо на летучей мыши, вы в значительной степени лишаете возможности запуска любого другого приложения система пока ваша включена.
Кроме того, разве это не заставит ОС выделять всю эту память и, как следствие, высвободить много памяти в пространство подкачки, что сильно замедлит запуск вашего приложения?
Это действительно хорошая практика?
operator new
дляnullptr
), если вы позволите мне сказать. Лучшее, что вы можете сделать с этой книгой, это зажечь дымоход. Выделение и освобождение большого блока памяти, конечно , не «очищает» память.new
оператор, чтобы возвращать ноль вместо броскаbad_alloc
. Если они этого не сделали, то да, этот код еще более бессмысленный: Poperator delete
требуется принятьnullptr
и рассматривать его как неоперативный. Любая глобальная перегрузка, которая не делает этого, сломана. Что означает, что это бессмысленно в любом случае. Точно так же, как предположение, что выделение огромного блока памяти и освобождение его «волшебным образом» принесут пользу. В лучшем случае это не принесет никакого вреда (скорее всего, поскольку страницы даже не затрагиваются ... в противном случае это может поменять некоторые страницы из вашего рабочего набора, которые вам необходимо будет перезагрузить позже).Ответы:
Единственное, что могло бы сделать предварительное выделение большого куска памяти , если на вашем компьютере недостаточно оперативной памяти, может заставить операционную систему освободить дополнительное пространство, переместив части памяти других программ на диск.
Поскольку такой обмен обычно является очень медленной операцией, которая в значительной степени замораживает вашу программу, пока она происходит, может быть некоторое преимущество в том, чтобы гарантировать, что, если это произойдет в любом случае, это произойдет до начала вашей игры, а не в середине игрового процесса.
Тем не менее, принудительное переключение на диск не является абсолютно надежным:
Во многих реализациях виртуальной памяти простое распределение памяти фактически не вызывает никакой подкачки; скорее это происходит только при первом доступе к каждой странице выделенной памяти. (Это, безусловно, верно в современных версиях Linux с включенной перегрузкой памяти, как это происходит по умолчанию; я не знаю точно, как разные версии Windows справляются с этим.)
Таким образом, если вы действительно хотите, чтобы этот код «очищал память», вам, вероятно, следует добавить
memset()
вызов или его эквивалент для фактической записи данных в каждую часть массива (или, по крайней мере, в его первыеphysicalRAMNeeded
байты) перед его освобождением.Кроме того, принуждение ОС к замене других программ из оперативной памяти таким образом не означает, что они останутся вне этой памяти. Windows является многозадачной ОС, и как только одна из этих замененных программ захочет снова запустить и использовать свои замененные данные, она снова будет заменена, что потенциально может снова заморозить вашу игру.
Таким образом, этот трюк, как правило, полезен только в том случае, если ОЗУ расходуется большими порциями данных, к которым нет активного доступа (например, большие документы остаются открытыми в фоновом режиме в некоторых программах редактирования). Веб-браузеры, как правило, особенно проблематичны в этом отношении, поскольку, даже если вы на самом деле не используете веб-страницу, открытую в какой-либо фоновой вкладке, на странице все равно могут быть запущены сценарии, которые заставляют ее храниться в оперативной памяти.
(Там являются способы программы на самом деле говорят ОС , чтобы зафиксировать часть своего пространства памяти в оперативную память и предотвратить его выгружен, но они , как правило , требуют повышенных привилегий. В любом случае, код размещен не кажется, используя любые такие методы.)
По сути, этот прием кажется полезным только в той относительно узкой пограничной ситуации, когда у пользователя будет достаточно ОЗУ для запуска вашей игры (и любого другого программного обеспечения, активно работающего в фоновом режиме) без подкачки, но в настоящее время ОЗУ заполнено неактивными и неиспользованными открытыми файлами. или другие данные, которые можно и нужно перенести на диск во время игры. В таких ситуациях это может быть эффективным, чтобы ваша игра выглядела более гладкой и более отзывчивой, заменяя случайные небольшие операции подкачки во время игры на одну во время запуска.
источник
Я не знаю, сколько лет этой записи, но я бы сказал, что она довольно старая. Я бы сказал, что в современных Windows (XP и новее, но особенно в 64-битных версиях) выполнение подобных действий мало повлияет на запуск вашей игры.
Прежде всего, помните, что адресное пространство виртуализируется для каждого процесса. Что касается вашего процесса, у вас есть все адресное пространство для себя, и вы всегда будете получать непрерывную (виртуальную) память, независимо от того, является ли эта память физически непрерывной или нет.
Фактически, является ли память непрерывной в физической памяти, это не то, что вы можете контролировать. ОС будет выбирать, как распределять физические блоки по своему усмотрению, и ничто из того, что вы делаете на уровне приложений, не может повлиять на преимущества (если таковые имеются) наличия непрерывной физической памяти.
Вам нужно заботиться о фрагментации виртуальной памяти, если вы продолжаете выделять и освобождать память разных размеров в течение очень длительного периода времени. Это, конечно, гораздо менее актуально для 64-битного адресного пространства. Игры обычно не запускаются месяцами, поэтому вам, скорее всего, не придется об этом заботиться, если только мы не говорим о долго работающих игровых серверах.
Даже если вы выделяете много памяти совершенно разных размеров на 32-разрядной машине, современные выделения памяти довольно хороши, поэтому маловероятно, что у вас возникнут проблемы фрагментации виртуальной памяти, если вы не будете активно их искать.
Если честно, я не знаю, о чем этот писатель. Даже если адресное пространство было разделено, и вы получили огромный непрерывный блок в физической памяти, освобождая его, вы говорите, что вам это больше не нужно. Есть другие программы, работающие в фоновом режиме, которые выполняют свои собственные выделения, поэтому, даже если ваш огромный malloc преуспел, никто не гарантирует, что следующая будет также успешной.
Я думаю, что это тот случай, когда «это сработало по какой-то причине, которую я не совсем понимаю, поэтому я придумал что-то, чтобы объяснить это».
источник