StackOverflowException в .NET

После нажатия нескольких элементов StackOverflowException в .NET я заметил, что они полностью обходят необработанные обработчики исключений, которые предлагает .NET(Application.ThreadException/AppDomain.UnhandledException). Это очень тревожно, так как у нас есть критический код очистки в этих обработчиках исключений.

Есть ли способ преодолеть это?

Ответ 1

Не совсем; переполнение стека или исключение из памяти в самой среде CLR означает, что что-то не так критично (я обычно получаю его, когда я был тупиком и создал рекурсивное свойство).

Когда это состояние возникает, CLR не может выделять новые вызовы функций или память, чтобы позволить ему вызывать в обработчики исключений; это "мы должны остановить сценарий сейчас".

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

Ответ 2

Существует три вида так называемых "асинхронных исключений". Это ThreadAbortException, исключение OutOfMemoryException и указанное исключение StackOverflowException. Эти исключения допускаются к любой инструкции в вашем коде.

И также есть способ их преодоления:

Простейшим является исключение ThreadAbortException. Когда текущий код выполняется в конечном блоке. ThreadAbortExceptions являются "перемещенными" до конца блока finally. Таким образом, все в конечном блоке нельзя прервать с помощью исключения ThreadAbortException.

Чтобы избежать исключения OutOfMemoryException, у вас есть только одна возможность: не выделяйте ничего в куче. Это означает, что вам не разрешено создавать новые ссылочные типы.

Чтобы преодолеть исключение StackOverflowException, вам нужна помощь от Framework. Эта помощь проявляется в зонах с ограниченным исполнением. Требуемый стек присваивается до, фактический код выполняется и дополнительно также гарантирует, что код уже JIT-скомпилирован и поэтому доступен для выполнения.

Существует три формы для выполнения кода в зонах с ограничениями выполнения (скопировано из Блог группы BCL):

  • ExecuteCodeWithGuaranteedCleanup - безопасная форма стека-переполнения try/finally.
  • Блок try/finally предшествует немедленно вызовом RuntimeHelpers.PrepareConstrainedRegions. Блок try не ограничен, но все блокировки, наконец, и блоки ошибок для этой попытки.
  • В качестве критического финализатора - любой подкласс CriticalFinalizerObject имеет финализатор, который готовится до того, как будет выделен экземпляр объекта.
    • Частным случаем является метод SafeHandle ReleaseHandle, виртуальный метод, который готов к приготовлению до выделения подкласса и вызван из критического финализатора SafeHandle.

Вы можете найти больше в этих сообщениях в блоге:

Ограниченные области выполнения и другие ошибки [Brian Grunkemeyer] в блоге Team BCL.

Joe Duffy Weblog о Атоматичность и асинхронные исключения исключений, где он дает очень хороший обзор асинхронных исключений и надежности в .net Framework.

Ответ 3

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

Единственное, что вы действительно можете сделать, это отследить причину и предотвратить ее вообще (например, быть осторожным с рекурсией и не выделять большие объекты в стеке).

Ответ 4

blowdart прибил его, выше. Рекурсивное свойство Dumbass, как он любит его называть. На самом деле проблема с набором кода слишком быстро.

private Thing _myThing = null;

Public Thing MyThing
{
   get{
        return this.MyThing;}
   set{
        this.MyThing = value;}
}