145
votes

In C++ it's actually possible to throw an exception by value without allocating memory on a heap, so this situation makes sense. But in .NET framework OutOfMemoryException is a reference type, therefore it is allocated on a heap. How does .NET framework allocates memory for OutOfMemoryException when there is not enough memory to create a new object?

2
Excellent question. Maybe enough memory is reserved for just that situation.GreatAndPowerfulOz
Just to add to the other answers already here, bear in mind that OOM means that the block you requested can't be allocated. If you ask for 100Mb and the largest available block the runtime can find is only 99Mb, it will fail. But an OOM exception only needs a few bytes of memory. So just because your allocation failed it doesn't mean there is zero memory left. But of course it is likely that the runtime reserves some memory to cover itself in this situationJason Williams
Your assumption about C++ is incorrect, by the way. Depending on the compiler, exceptions may well be allocated on the heap. The MS compiler does not, but in the Common C++ ABI, exceptions are allocated on the heap, except that there is a small preallocated emergency buffer that will be used instead if there's no space left on the heap.Sebastian Redl

2 Answers

164
votes

It is preallocated by the runtime. If you explore the heap of any managed process you'll find an instance of that exception.

Here are the preallocated exceptions of a Hello World app:

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
42
votes

When an out-of-memory condition is encountered inside the runtime, it calls ThrowOutOfMemory. This calls Exception::GetOOMException, which constructs the object on the stack and then copies it to a statically-allocated global instance, which is then thrown.

This is not the managed Exception, though, it a C++ exception declared in ex.h. C++ Exceptions are converted to managed Exceptions in clrex.cpp, which contains code to specifically throw the preallocated managed OutOfMemoryException, which was originally allocated and constructed in appdomain.cpp.

Note: Some of these source files are large and may hang your browser for several seconds while it loads the syntax highlighting.

The call sites that Tim Schmelter linked in a comment on the other answer aren't related to the runtime running out of memory and being unable to construct an object.