Как .NET Framework выделяет память для OutOfMemoryException?

144

В C ++ на самом деле можно генерировать исключение по значению без выделения памяти в куче, поэтому такая ситуация имеет смысл. Но в .NET Framework OutOfMemoryExceptionэто ссылочный тип, поэтому он расположен на куче. Как .NET Framework выделяет память для OutOfMemoryExceptionслучаев, когда не хватает памяти для создания нового объекта?

RX_DID_RX
источник
6
Отличный вопрос. Может быть, достаточно памяти зарезервировано только для этой ситуации.
GreatAndPowerfulOz 30.10.15
19
Просто добавьте к другим ответам, которые уже здесь, имейте в виду, что OOM означает, что запрашиваемый вами блок не может быть выделен. Если вы запрашиваете 100 МБ и самый большой доступный блок, который может найти среда выполнения, составляет всего 99 МБ, он потерпит неудачу. Но для исключения OOM требуется всего несколько байтов памяти. То есть, если ваше выделение не удалось, это не значит, что осталась нулевая память. Но, конечно, вполне вероятно, что среда выполнения оставляет за собой некоторую память, чтобы покрыть себя в этой ситуации
Джейсон Уильямс
4
Кстати, ваше предположение о C ++ неверно. В зависимости от компилятора исключения могут быть размещены в куче. Компилятор MS не делает этого, но в Common C ++ ABI исключения размещаются в куче, за исключением того, что есть небольшой предварительно выделенный аварийный буфер, который будет использоваться вместо этого, если в куче не осталось места.
Себастьян Редл

Ответы:

163

Он предварительно выделяется средой выполнения. Если вы исследуете кучу любого управляемого процесса, вы найдете экземпляр этого исключения.

Вот предварительно выделенные исключения приложения 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
Брайан Расмуссен
источник
4
Но конструкторOutOfMemoryException называется.
Тим Шмелтер
36
Среда выполнения не должна играть по тем же правилам, что и ваш код. Другой пример: если вы бросаете, StackOverflowExceptionвы можете поймать его, но если среда выполнения выдает это исключение, вы не можете его поймать (по умолчанию).
Брайан Расмуссен
8
Большая часть базовых механизмов CLR фактически написана на «C» и «C ++». Таким образом, вполне возможно, что объект «новый» на месте или память управляется иным образом.
GreatAndPowerfulOz 30.10.15
2
@hvd Какой побочный эффект? OOM дает трассировку стека? Хотелось бы, чтобы остальная информация была довольно статичной?
Джеймс Баррасс
7
Что делать, если требуются два исключения из тех же типов, потому что два потока выдают их одновременно?
Traubenfuchs
42

Когда во время выполнения возникает условие нехватки памяти, он вызывает ThrowOutOfMemory . Это вызывает Exception :: GetOOMException , который создает объект в стеке, а затем копирует его в статически размещенный глобальный экземпляр, который затем генерируется.

Это не удалось Exception, хотя, это исключение C ++ объявлено в ex.h . Исключения C ++ преобразуются в управляемые исключения в clrex.cpp , который содержит код, который специально генерирует предварительно выделенное управляемое исключение OutOfMemoryException, которое изначально было размещено и создано в appdomain.cpp .

Примечание. Некоторые из этих исходных файлов имеют большой размер и могут зависать в браузере на несколько секунд, пока загружается подсветка синтаксиса.

Сайты вызовов, которые Тим Шмельтер связал в комментарии к другому ответу, не связаны с тем, что во время выполнения не хватает памяти и невозможности создать объект.

Random832
источник