C# поймать исключение переполнения стека

Я получил рекурсивный вызов метода, который вызывает исключение переполнения стека. Первый звонок окружен блоком try catch, но исключение не поймано.

ведет ли себя исключение переполнения стека особым образом ? Могу ли я правильно поймать / обработать исключение ?

NB : если актуально :

  • исключение не выбрасывается в основной поток

  • объект, где код бросает исключение вручную загружается сборкой.LoadFrom(...).Метод createinstance(...)

9 ответов


начиная с 2.0 исключение StackOverflow может быть поймано только в следующих обстоятельствах.

  1. среда CLR запускается в размещенной среде, где хост специально позволяет обрабатывать исключения StackOverflow
  2. исключение stackoverflow создается кодом пользователя, а не из-за фактической ситуации переполнения стека (ссылка)

правильный способ-исправить переполнение, но....

Вы можете дать себе большую стопку:-

using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();

Вы можете использовать системы.Диагностика.Свойство stacktrace FrameCount для подсчета используемых кадров и создания собственного исключения при достижении предела кадра.

или, вы можете рассчитать размер оставшегося стека и бросить свое собственное исключение, когда оно падает ниже порога:-

class Program
{
    static int n;
    static int topOfStack;
    const int stackSize = 1000000; // Default?

    // The func is 76 bytes, but we need space to unwind the exception.
    const int spaceRequired = 18*1024; 

    unsafe static void Main(string[] args)
    {
        int var;
        topOfStack = (int)&var;

        n=0;
        recurse();
    }

    unsafe static void recurse()
    {
        int remaining;
        remaining = stackSize - (topOfStack - (int)&remaining);
        if (remaining < spaceRequired)
            throw new Exception("Cheese");
        n++;
        recurse();
    }
}

просто поймать сыр. ;)


со страницы MSDN на StackOverflowExceptions:

в предыдущих версиях .NET Основы, ваше приложение может поймать объект StackOverflowException (например, для восстановления неограниченная рекурсия). Однако, это практика в настоящее время не поощряется потому что значительный дополнительный код требуется надежно поймать стек исключение переполнения и продолжить выполнение программы.

начиная с .NET Рамки версия 2.0, исключение StackOverflowException объект не может быть пойман try-catch блок и соответствующий процесс прекращена по умолчанию. Следовательно, пользователям рекомендуется написать свой код обнаружение и предотвращение стека переполнение. Например, если ваш применение зависит от рекурсии, использования счетчик или состояние для завершите рекурсивный цикл. Отмечать это приложение, которое размещает общеязыковая среда выполнения (CLR) может укажите, что среда CLR выгружает домен приложения, в котором находится стек возникает исключение переполнения, и пусть соответствующий процесс продолжается. Для более подробную информацию см. Интерфейс ICLRPolicyManager и Размещения среды CLR.


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

для этого вам нужно открыть Настройки исключений из меню "отладка". В более старых версиях Visual Studio это "отладка" - "исключения"; в более новых версиях это "отладка" - "Windows" - "настройки исключений".

после открытия настроек разверните 'Исключения среды CLR, расширению "системы", прокрутите вниз и проверить систему.StackOverflowException'. Затем вы можете посмотреть на стек вызовов и найти повторяющийся шаблон вызовов. Это должно дать вам представление о том, где искать, чтобы исправить код, вызывающий переполнение стека.


Как упоминалось выше несколько раз, невозможно поймать StackOverflowException, которое было вызвано системой из-за поврежденного состояния процесса. Но есть способ заметить исключение как событие:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

начиная с .NET Framework версии 4, это событие не вызывается для исключений, которые повреждают состояние процесса, например переполнения стека или нарушения доступа, если обработчик событий не критичен для безопасности и имеет атрибут HandleProcessCorruptedStateExceptionsattribute.

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

в .NET Framework версий 1.0 и 1.1 необработанное исключение, которое происходит в поток, отличный от основного потока приложения, перехватывается средой выполнения и поэтому не вызывает завершения приложения. Таким образом, событие UnhandledException может быть вызвано без завершения приложения. Начиная с .NET Framework версии 2.0, эта остановка для необработанных исключений в дочерних потоках была удалена, поскольку кумулятивный эффект таких тихих сбоев включал снижение производительности, поврежденные данные и блокировки, все из которых было трудно отлаживать. Дополнительные сведения, включая список случаев, в которых среда выполнения не завершается, см. В разделе исключения в управляемых потоках.


да из переполнения стека CLR 2.0 считается не восстанавливаемой ситуацией. Таким образом, среда выполнения все еще завершает процесс.

для деталей пожалуйста см. документацию http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx


ты не можешь. CLR не позволит вам. Переполнение стека является фатальной ошибкой и не может быть восстановлено.


вы не можете, поскольку большинство сообщений объясняют, позвольте мне добавить еще одну область:

на многих веб-сайтах вы найдете людей, говорящих, что способ избежать этого-использовать другой AppDomain, поэтому, если это произойдет, домен будет выгружен. Это абсолютно неправильно (если вы не размещаете свою среду CLR), поскольку поведение среды CLR по умолчанию вызовет событие KillProcess, сбивая ваш AppDomain по умолчанию.


Это невозможно, и по уважительной причине (для одного, подумайте обо всех этих catch(Exception){} вокруг).

Если вы хотите продолжить выполнение после переполнения стека, запустите опасный код в другом AppDomain. Политики CLR могут быть установлены для завершения текущего AppDomain при переполнении, не затрагивая исходный домен.