Como o .NET framework aloca memória para OutOfMemoryException?

144

No C ++, é realmente possível lançar uma exceção por valor sem alocar memória em uma pilha, portanto, essa situação faz sentido. Mas no .NET framework OutOfMemoryExceptioné um tipo de referência, portanto, ele é alocado em um heap. Como o .NET framework aloca memória para OutOfMemoryExceptionquando não há memória suficiente para criar um novo objeto?

RX_DID_RX
fonte
6
Excelente pergunta. Talvez haja memória suficiente reservada apenas para essa situação.
GreatAndPowerfulOz
19
Apenas para adicionar às outras respostas já aqui, lembre-se de que OOM significa que o bloco que você solicitou não pode ser alocado. Se você pedir 100 Mb e o maior bloco disponível que o tempo de execução conseguir encontrar for de apenas 99 Mb, ele falhará. Mas uma exceção OOM precisa apenas de alguns bytes de memória. Portanto, apenas porque sua alocação falhou, isso não significa que resta zero memória. Mas é claro que é provável que o tempo de execução reserve um pouco de memória para se cobrir nessa situação
Jason Williams
4
Sua suposição sobre C ++ está incorreta, a propósito. Dependendo do compilador, as exceções podem muito bem ser alocadas no heap. O compilador MS não, mas na ABI C ++ comum, as exceções são alocadas no heap, exceto que há um pequeno buffer de emergência pré-alocado que será usado em vez disso, se não houver espaço restante no heap.
Sebastian Redl

Respostas:

163

É pré-alocado pelo tempo de execução. Se você explorar a pilha de qualquer processo gerenciado, encontrará uma instância dessa exceção.

Aqui estão as exceções pré-alocadas de um aplicativo Hello World:

0:003> !dumpheap -stat -type Exception
Statistics:
      MT    Count    TotalSize Class Name
735f2920        1           84 System.ExecutionEngineException
735f28dc        1           84 System.StackOverflowException
735f2898        1           84 System.OutOfMemoryException
735f2744        1           84 System.Exception
735f2964        2          168 System.Threading.ThreadAbortException
Brian Rasmussen
fonte
4
Mas o construtor deOutOfMemoryException é chamado.
Tim Schmelter
36
O tempo de execução não precisa ser reproduzido pelas mesmas regras do seu código. Outro exemplo é que, se você jogar, StackOverflowExceptionpoderá pegá-lo, mas se o tempo de execução lançar essa exceção, não poderá pegá-lo (por padrão).
Brian Rasmussen
8
Muitos dos mecanismos subjacentes do CLR são realmente escritos em "C" e "C ++". Portanto, é perfeitamente possível que o objeto seja "novo no local" ou que a memória seja manipulada.
GreatAndPowerfulOz
2
@hvd Qual é o efeito colateral? OOM fornece um rastreamento de pilha? Eu teria que o restante das informações seja bastante estática?
James Barrass
7
E se duas exceções daqueles com o mesmo tipo forem necessárias porque dois threads as lançam ao mesmo tempo?
Traubenfuchs
42

Quando uma condição de falta de memória é encontrada dentro do tempo de execução, chama ThrowOutOfMemory . Isso chama Exception :: GetOOMException , que constrói o objeto na pilha e o copia para uma instância global alocada estaticamente, que é lançada.

Esta não é a exceção gerenciada, porém, uma exceção de C ++ declarada em ex.h . As exceções do C ++ são convertidas em exceções gerenciadas no clrex.cpp , que contém o código para lançar especificamente a OutOfMemoryException gerenciada pré- alocada, originalmente alocada e construída em appdomain.cpp .

Nota: Alguns desses arquivos de origem são grandes e podem travar o navegador por alguns segundos enquanto carrega o realce da sintaxe.

Os sites de ligação que Tim Schmelter vinculou em um comentário sobre a outra resposta não estão relacionados ao tempo de execução da memória e à incapacidade de construir um objeto.

Random832
fonte