Znam kilka gier napisanych w C ++, ale nie używających wyjątków. Ponieważ obsługa awarii alokacji pamięci w C ++ jest generalnie oparta na std::bad_alloc
wyjątku, w jaki sposób te gry radzą sobie z taką awarią?
Czy po prostu ulegają awarii, czy istnieje inny sposób radzenia sobie z błędem braku pamięci?
c++
resource-management
memory
użytkownik200783
źródło
źródło
std::terminate
i to wszystko. Ale następnie pod tym samym ograniczeniem alokacja może zwrócić wskaźnik zerowy zamiast zgłaszania wyjątku, a wynik ten można sprawdzić i obsłużyć osobno.ClassName variableName = new(nothrow) ClassName();
( oczywiście zastępując nazwę klasy, nazwę zmiennej itp. ). Następnie, jeśli alokacja nie powiedzie się, możesz to wykryć, mówiąc,if(!variableName)
że można obsłużyć błąd bez bloku wyjątku try-catch. Podobnie, jeżeli pamięć jest przeznaczona użyciu funkcji takich jakmalloc()
,calloc()
itp, a następnie awarii przydzielić można wykryć stosując ten samif(!variableName)
sposób bez potrzeby try-haczyk. Jeśli chodzi o sposób, w jaki gry radzą sobie z tymi błędami, to w tym momencie twórcy gry decydują, czy ulegnie awarii, czy nie.Odpowiedzi:
Tak samo jak wszystkie przeciętne programy: nie. *
W przypadku większości aplikacji nie oczekuje się od klientów kontynuowania pracy po wyczerpaniu pamięci. Wszystkie gry należą do tych „większości aplikacji”. Nie ma sensu poświęcanie czasu i pieniędzy na pracę przy wyjątkowej walizce, której klient nie oczekuje od pracy.
Pytanie jest podobne do następującego:
Odpowiedź jest taka sama: są to problemy użytkowników. Ta gra nie obchodzi.
* W rzeczywistości zazwyczaj przechwytują wyjątek na wysokim poziomie i wykorzystują pamięć, która została wstępnie przydzielona na początku gry, aby spróbować zarejestrować zdarzenie przed zawieszeniem / zakończeniem. Następnie dziennik pozwala obsłudze klienta tracić mniej czasu na problem.
źródło
Zazwyczaj tego rodzaju scenariusz nigdy się nie zdarza.
Po pierwsze, pamięć wirtualna we współczesnych systemach operacyjnych oznacza, że i tak jest mało prawdopodobne w normalnej pracy; chyba że wystąpi błąd niekontrolowanej alokacji, gra będzie alokowała pamięć z wirtualnej przestrzeni adresowej systemu operacyjnego, a system operacyjny będzie sprawdzał wprowadzanie i wyłączanie stronicowania.
To wszystko dobrze i dobrze, ale tak naprawdę nie dotyczy to konsol ani starszych systemów operacyjnych, więc po drugie, gry nawet nie wykonują wielu małych dynamicznych alokacji przy użyciu standardowych alokatorów bibliotecznych. Zamiast tego będą jednorazowo przydzielać dużą pulę pamięci podczas uruchamiania i pobierać z tej puli wszelkie wymagane alokacje środowiska wykonawczego (np. Używając nowego umieszczenia C ++ lub pisząc własny system zarządzania pamięcią na na początku).
To także chroni przed wyciekiem pamięci, ponieważ zamiast śledzić i rozliczać każde małe indywidualne przydziały, gra może po prostu wyrzucić całą pulę, aby odzyskać pamięć.
I po trzecie, gry zawsze ustalają minimalną specyfikację i w ramach tego budżetują zużycie pamięci. Jeśli więc gra wymaga 1 GB pamięci RAM, oznacza to, że dopóki jej użycie pamięci nigdy nie przekroczy 1 GB, nigdy nie musi się martwić, że zabraknie pamięci RAM.
źródło
Cóż, głównie w ten sam sposób, w jaki to zrobiliśmy, zanim istniały wyjątki - stare „sprawdź podejście do wartości zwrotu”. Jeśli alokator nie korzysta z wyjątków, zwykle powraca,
null
gdy alokacja się nie powiedzie. Sprawdzona gra sprawdzi to i poradzi sobie z sytuacją w bezpieczny sposób. Czasami oznacza to zakończenie gry (np.std::terminate
) Lub przynajmniej powrót do ostatniego znanego bezpiecznego stanu (np. Kiedy przydzielisz z puli, możesz bezpiecznie pozbyć się całej puli, nawet gdy jest ona w niebezpiecznym stanie).Wiele gier korzysta nawet z wyjątków w takich przypadkach. Kiedy ktoś mówi „unikaj stosowania wyjątków w kodzie gry”, zwykle oznacza to „używaj wyjątków tylko w naprawdę wyjątkowych przypadkach, a nie w przypadku zwykłej kontroli przepływu”. Konfiguracja wychwytywania wyjątku braku pamięci jest tania - koszty są głównie związane z tym problemem i komplikacjami związanymi z obsługą wyjątku. Żadne z nich nie jest bardzo ważne w typowym przypadku braku pamięci - prawie zawsze i tak chcesz zakończyć.
Pamiętaj, że większość gier ulegnie awarii. To nie jest tak szalone, jak się wydaje - zwykle używasz pamięci jako celu i upewnij się, że twoja gra nie osiąga tego limitu (na przykład, stosując limit liczby jednostek w grze RTS lub ograniczając ilość wrogów w sekcji FPS). Nawet jeśli tego nie zrobisz, zwykle nie brakuje pamięci w żadnym stosunkowo nowoczesnym systemie - na przykład brakuje wirtualnej przestrzeni adresowej (w aplikacji 32-bitowej) lub stosu. System operacyjny już udaje, że masz tyle pamięci, ile prosisz - to jedna z abstrakcji, jaką zapewnia pamięć wirtualna. Chodzi o to, że to, że masz 256 MiB fizycznej pamięci RAM, nie oznacza, że twoja aplikacja nie może użyć 4 GiB pamięci. Niektóre gry mogą nawet nie mieć nic przeciwko temu, że wszystkie ich dane nie są
źródło
Łapanie wyjątku i podejmowanie decyzji, co zrobić, kiedy zostanie zgłoszony wyjątek, to dwie różne rzeczy.
Musisz mieć złożoną logikę, aby zwolnić pamięć, która nie jest potrzebna Twojemu programowi. Co gorsza, jeśli jakiś inny uruchomiony program lub biblioteka wycieka z pamięci, nie masz nad nią kontroli
Jedyną dobrą rzeczą, którą możesz zrobić, aby zamknąć się z wdziękiem i to właśnie zdecyduje większość programów. Nie możesz nawet zdecydować się poczekać, aż pamięć będzie dostępna, ponieważ spowoduje to brak reakcji Twojego programu.
źródło
std::terminate
i to wszystko. Ale w takich warunkach alokacja może zwrócić wskaźnik zerowy zamiast zgłaszania wyjątku i może być obsługiwana osobno.