После нескольких StackOverflowExceptions в .NET я заметил, что они полностью обходят необработанные обработчики исключений, которые предлагает .NET (Application.ThreadException / AppDomain.UnhandledException). Это очень беспокоит, поскольку у нас есть критический код очистки в этих обработчиках исключений.
Не совсем; переполнение стека или исключение нехватки памяти в самой среде CLR означает, что что-то пошло не так (я обычно получаю это, когда был тупицей и создал рекурсивное свойство).
Когда возникает это состояние, среда CLR не может выделить новые вызовы функций или память, чтобы позволить ей вызывать обработчики исключений; это сценарий "мы должны остановить сейчас".
Однако если вы сами вызовете исключение, будут вызваны ваши обработчики исключений.
Ответ 2 · рейтинг 25 · Thomas Danecker
Есть три вида так называемых "асинхронных исключений". Это ThreadAbortException, OutOfMemoryException и упомянутое StackOverflowException. Эти исключения могут возникать при любой инструкции в вашем коде.
И есть способ их преодолеть:
Самый простой - ThreadAbortException. Когда текущий код выполняется в finally-блоке. ThreadAbortExceptions как бы "перемещены" в конец блока finally. Таким образом, все в блоке finally не может быть прервано исключением ThreadAbortException.
Чтобы избежать OutOfMemoryException, у вас есть только одна возможность: ничего не размещать в куче. Это означает, что вам не разрешено создавать какие-либо новые ссылочные типы.
Чтобы преодолеть StackOverflowException, вам понадобится помощь от Framework. Эта помощь проявляется в областях ограниченного выполнения. Требуемый стек выделяется до фактического выполнения кода и дополнительно гарантирует, что код уже JIT-скомпилирован и поэтому доступен для выполнения.
Есть три формы для выполнения кода в ограниченных областях выполнения (скопированы из Блог команды BCL):
ExecuteCodeWithGuaranteedCleanup, безопасная для переполнения стека форма try / finally.
Блоку try / finally непосредственно предшествует вызов RuntimeHelpers.PrepareConstrainedRegions. Блок try не ограничен, но есть все блоки catch, finally и fault для этой попытки.
As a critical finalizer - any subclass of CriticalFinalizerObject has a finalizer that is eagerly prepared before an instance of the object is allocated.
A special case is SafeHandle's ReleaseHandle method, a virtual method that is eagerly prepared before the subclass is allocated, and called from SafeHandle's critical finalizer.
Переполнение стека - это не то, что вы можете просто восстановить, поскольку он не может выделить больше памяти стека даже для вызова вашего обработчика исключений.
Единственное, что вы действительно можете сделать, - это отследить причину и предотвратить ее вообще (например, будьте осторожны с рекурсией и не размещайте большие объекты в стеке).
Ответ 4 · рейтинг 1 · NBB
Blowdart прибил это выше. Рекурсивное свойство тупицы, как он любит это называть. На самом деле проблема с набором кода слишком быстро.