Książka Game Coding Complete, czwarta edycja , rozdział 5 ( Inicjalizacja i zamknięcie gry ), sekcja Sprawdzanie pamięci zawiera ten interesujący przykładowy kod:
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;
}
}
Rodzi to kilka pytań.
Pierwsza część pyta tylko system operacyjny (Windows), ile fizycznej pamięci RAM jest dostępne. Ciekawą częścią jest druga, która przydziela ogromną część pamięci i od razu ją uwalnia:
char *buff = GCC_NEW char[virtualRAMNeeded];
if (buff)
{
delete[] buff;
}
Autor wyjaśnia dalej:
... ta funkcja przydziela i natychmiast uwalnia ogromny blok pamięci. Powoduje to, że system Windows usuwa wszelkie śmieci nagromadzone w menedżerze pamięci i dwukrotnie sprawdza, czy można przydzielić ciągły blok tak duży, jak potrzebujesz. Jeśli połączenie się powiedzie, w zasadzie uruchamiasz odpowiednik maszyny Zamboni w pamięci systemu, przygotowując ją do uderzenia w lód ...
Ale mam co do tego zastrzeżenia.
„Czyścisz śmieci, które nagromadziły się w menedżerze pamięci?” Naprawdę? Jeśli gra właśnie się rozpoczęła, czy nie powinno być śmieci?
„Upewnij się, że możesz przydzielić ciągły blok?” W bardzo szczególnym przypadku, w którym zamierzasz samodzielnie zarządzać pamięcią, miałoby to jakiś sens, ale mimo to, jeśli przydzielisz dużo pamięci bezpośrednio od nietoperza, praktycznie uniemożliwisz uruchomienie innej aplikacji system, gdy twój jest włączony.
Ponadto, czy nie zmusi to systemu operacyjnego do zatwierdzenia całej pamięci, aw konsekwencji spowoduje wyrzucenie dużej ilości pamięci na miejsce na dysku wymiany, co spowalnia uruchomienie aplikacji?
Czy to naprawdę dobra praktyka?
operator new
dla nullptr
), jeśli pozwolisz mi powiedzieć. Najlepszą rzeczą, jaką możesz zrobić z tą książką, jest rozpalenie komina. Przydzielanie i zwalnianie dużego bloku pamięci oczywiście nie „oczyszcza” pamięci.
new
operatora, aby zwrócił wartość zero zamiast rzucać bad_alloc
. Jeśli nie, to tak, ten kod jest jeszcze bardziej bezsensowny: P
operator delete
jest , należy zaakceptować nullptr
i potraktować to jako brak możliwości. Każde globalne przeciążenie, które tego nie robi, jest zepsute. Co oznacza, że jest to nonsensowne w obu przypadkach. Podobnie jak założenie, że przydzielenie ogromnego bloku pamięci i zwolnienie go „magicznie” zrobi coś dobrego. W najlepszym wypadku nie zaszkodzi (najprawdopodobniej, ponieważ strony nie są nawet dotykane ... w przeciwnym razie może zamienić niektóre strony z zestawu roboczego, które trzeba będzie ponownie załadować).