Estou ciente de vários jogos que são escritos em C ++, mas não usam exceções. Como o tratamento da falha de alocação de memória no C ++ geralmente é criado em torno da std::bad_alloc
exceção, como esses jogos lidam com essa falha?
Eles simplesmente travam ou existe outra maneira de lidar e se recuperar de um erro de falta de memória?
c++
resource-management
memory
user200783
fonte
fonte
std::terminate
, e é isso. Mas, sob a mesma restrição, a alocação pode retornar um ponteiro nulo em vez de lançar uma exceção, e esse resultado pode ser verificado e tratado separadamente.ClassName variableName = new(nothrow) ClassName();
( obviamente, substituindo o nome da classe, o nome da variável etc. ). Se a alocação falhar, você poderá detectá-lo dizendoif(!variableName)
permitindo que o erro seja tratado sem um bloco de exceção try-catch. Da mesma forma, se a memória é alocada usando uma função comomalloc()
,calloc()
etc., as falhas na alocação podem ser detectadas usando o mesmoif(!variableName)
método sem a necessidade de uma tentativa de captura. Quanto à forma como os jogos lidam com esses erros, bem, nesse ponto, cabe aos desenvolvedores decidir se ele trava ou não.Respostas:
O mesmo que todos os programas comuns: eles não. *
Para a maioria dos aplicativos, não há expectativa de que eles continuem trabalhando quando a memória acabar. Todos os jogos se enquadram nessas "maioria dos aplicativos". Gastar tempo e dinheiro para trabalhar em um caso de ponta que o cliente não espera trabalhar não faz sentido.
A pergunta é semelhante à seguinte:
A resposta é a mesma: estes são os problemas dos usuários. O jogo não se importa.
* Na verdade, eles geralmente capturam a exceção de alto nível e usam a memória pré-alocada no início do jogo para tentar registrar o evento antes de travar / terminar. O log permite que o suporte ao cliente perca menos tempo com o problema.
fonte
Normalmente, esse tipo de cenário nunca acontece.
Em primeiro lugar, a memória virtual em sistemas operacionais modernos significa que é altamente improvável que ocorra na operação normal de qualquer maneira; a menos que você tenha um erro de alocação descontrolada, o jogo alocará memória do espaço de endereço virtual do SO e o SO cuidará da paginação dentro e fora.
Está tudo bem, mas na verdade não se aplica a consoles ou sistemas operacionais mais antigos; portanto, em segundo lugar, os jogos nem fazem muitas pequenas alocações dinâmicas usando alocadores de biblioteca padrão de qualquer maneira. Em vez disso, o que eles farão é alocar um grande conjunto de memória apenas uma vez na inicialização e retirar desse pool qualquer alocação de tempo de execução necessária (por exemplo, usando o posicionamento C ++ novo ou escrevendo seu próprio sistema de gerenciamento de memória em em cima).
Isso também protege contra vazamentos de memória porque, em vez de ter que rastrear e contabilizar cada alocação individual pequena, um jogo pode simplesmente jogar fora todo o pool para recuperar a memória.
E em terceiro lugar, os jogos sempre definirão uma especificação mínima e incluirão no orçamento seu uso de memória. Portanto, se um jogo for especificado para exigir 1 GB de RAM, isso significa que, enquanto o uso da memória nunca exceder 1 GB, ele nunca precisará se preocupar com a falta de RAM.
fonte
Bem, principalmente, da mesma maneira que fizemos antes das exceções - o antigo "verifique a abordagem do valor de retorno". Se um alocador não usar exceções, geralmente retornará
null
quando uma alocação falhar. Um jogo bem escrito verificará isso e lidará com a situação da maneira que for mais segura. Às vezes, isso significa encerrar o jogo (por exemplostd::terminate
) ou, pelo menos, reverter para o último estado seguro conhecido (por exemplo, quando você aloca a partir de um pool, você pode descartar com segurança todo o pool mesmo quando este estiver em um estado inseguro).Muitos jogos usam exceções para casos como esse mesmo então. Quando alguém diz "evite usar exceções no código do jogo", o que geralmente significa é "use somente exceções para casos verdadeiramente excepcionais, não para controle de fluxo mundano". A configuração para capturar uma exceção de falta de memória é barata - o custo é maioritariamente e as complicações que você obtém ao lidar com a exceção. Nenhum deles é muito importante em um caso típico de falta de memória - você quase sempre deseja terminar de qualquer maneira.
Lembre-se, a maioria dos jogos irá falhar. Isso não é tão louco quanto parece - você normalmente usa um pouco de memória como alvo e garante que seu jogo não atinja esse limite (por exemplo, usando um limite de contagem de unidades em um jogo RTS ou limitando o quantidade de inimigos em uma seção de um FPS). Mesmo se não o fizer, normalmente não fica sem memória em nenhum sistema razoavelmente moderno - fica sem espaço de endereço virtual (em um aplicativo de 32 bits) ou na pilha, por exemplo. O sistema operacional já finge que você tem tanta memória quanto solicita - essa é uma das abstrações que a memória virtual fornece. O ponto é que, apenas porque você tem 256 MiB de RAM física, isso não significa que seu aplicativo não pode usar 4 GiB de memória. Alguns jogos podem nem se importar muito com o fato de todos os dados não estarem '
fonte
Capturar uma exceção e decidir fazer o que quando e exceção é gerada são duas coisas diferentes.
Você precisa ter uma lógica complexa para liberar memória que não é necessária pelo seu programa. Pior ainda, se algum outro programa ou biblioteca em execução estiver vazando na memória, você não terá controle sobre ele
A única coisa boa que você pode fazer é desligar o dispositivo normalmente e é isso que a maioria dos programas escolherá fazer. Você nem pode decidir esperar até que a memória esteja disponível, pois isso tornará seu programa sem resposta.
fonte
std::terminate
, e é isso. Mas nessas condições, a alocação pode retornar um ponteiro nulo em vez de lançar uma exceção, e isso pode ser tratado separadamente.