Как отладить исключение stackoverflow в .NET - PullRequest
33 голосов
/ 19 января 2011

Сценарий:

Я только что работал и реализовал кучу кода, но когда я его выполняю, я получаю исключение StackOverflowException?У StackOverflowException нет стековой трассировки, поэтому я застрял.Я знаю, почему может произойти переполнение стека, но чтобы это исправить, мне нужно знать, где находится корень.

Все, что я получаю, это: необработанное исключение типа 'System.StackOverflowException' произошло в tag-you-it.dll

Параметры:

  1. Просканируйте все изменения и попытайтесь определить причину проблемы.(может быть медленным)
  2. Используйте отладчик и переходите, пока не найдете проблему.(вероятно, лучше, чем 1.)
  3. Используйте профиль и найдите наиболее вызываемые методы.
  4. ?

PS:

Это гипотетическая ситуация (хотя и не слишком редкая), поэтому код недоступен.

Ответы [ 10 ]

16 голосов
/ 19 января 2011

Это почти всегда из-за рекурсии. Либо метод, вызывающий сам себя, либо метод, вызывающий метод, который вызывает его обратно и т. Д.

Чтобы найти его:

  • ОБНОВЛЕНО : Я не осознавал, но, очевидно, вы не можете получить трассировку стека для StackOverflowException (я думаю, что-то связанное с неспособностью поймать его). Однако есть способы получить дамп , как упомянуто здесь .
  • ReSharper покажет методы, которые вызывают себя (он помещает маленький зеленый кружок в боковую панель для рекурсивных вызовов), хотя он не поймает рекурсию, если задействованы два или более методов.
  • Используйте такой инструмент, как ANTS Profiler, чтобы увидеть, какие методы вызываются чаще всего.
  • Следите за событиями, которые могут вызывать код, который означает, что то же самое событие запускается снова, вызывая цикл.

Иногда вы можете получить опечатки, подобные этой:

private string name;

public string Name
{
    get { return Name; } // Ooops! This is recursive, all because of a typo...
}

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

11 голосов
/ 17 апреля 2018

WinDbg может выполнить свою работу, в том числе даже получить разумную (clr) трассировку стека.Вам нужно получить WinDbg , если вы не установили его вместе с Visual Studio или Windows SDK.Примечание: «Предварительный просмотр WinDbg» с новым графическим интерфейсом работал для меня нормально.

Я предлагаю запустить ваш процесс из WinDbg, но, конечно, вы также можете присоединить его к запущенному процессу, если вам это подходит лучше.

Примечание. Сразу после запуска процесса CLR не загружается, и .loadby SOS.dll clr завершается ошибкой («невозможно найти модуль« clr »). Необходимо дождаться загрузки CLR. Чтобы остановить выполнениекак только это произойдет, выполните:

  • sxe ld clr

После загрузки CLR вам нужно будет выполнить следующие шаги, чтобы перейти на SackOverflowException (введите вкомандное окно / строка):

  • .loadby SOS.dll clr ( not .loadby sos clr - это может привести к двойной загрузке расширения)
  • !stoponexception -create System.StackOverflowException
  • g (продолжает отладку)

вызывает исключение StackOverflowException / ожидает его возникновения

  • !clrstack (будетнапечатайте трассировку стека)

Известные источники:

8 голосов
/ 15 февраля 2011

Перейдите в раздел «Отладка, исключения» и установите флажок «Общие исключения времени выполнения языка». Теперь, когда вы вызываете исключение stackoverflow, отладчик остановится (в конце концов) и покажет вам стек вызовов.

5 голосов
/ 19 января 2011

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

3 голосов
/ 15 января 2019

Утилита ProcDump помогла нам отладить проблему как , подробно описанную здесь . Шаги:

  1. Скачать инструмент
  2. Запустите процесс, запишите его идентификатор
  3. Присоедините отладчик, запустив procdump -accepteula -e 1 -f C00000FD.STACK_OVERFLOW -g -ma <process ID> d:\home\DebugTools\Dumps (каталог должен существовать)
  4. Сделайте исключение, которое произойдет, и процедура сделает вас дампом.
  5. Откройте файл дампа в Visual Studio. Для моего примера приложения сразу после открытия файла дампа VS выделил строку, на которой произошло SO.

Мы можем использовать ту же технику в Azure, включив расширение CrashDiagnoser , например, , описанное здесь . В основном он выполняет те же действия, что и выше. Создаваемый им дамп-файл можно загрузить и открыть в Visual Studio.

1 голос
/ 19 января 2011

В методе, который является «точкой входа» в операцию, которая завершается неудачей, установите точку останова.Пройдите по коду и следите за появлением одной и той же последовательности вызовов методов, повторяющихся снова и снова в одном и том же шаблоне, чтобы стек вызовов становился все глубже и глубже.текущее местоположение, где бы это ни было.Продолжить выполнение (F5 в Visual Studio) - если вы находитесь на правильном пути, то отладчик очень быстро остановится в том же месте, а стек вызовов станет еще глубже."кадр стека, который вы можете изучить, чтобы выяснить, как обеспечить правильное завершение этой рекурсии.

0 голосов
/ 13 марта 2019

Просто хотел добавить к ответу об использовании WinDbg то, что я нашел для отладки dotnet core приложения

  1. убедитесь, что у вас установлен windbg
  2. запустите ваше приложение через командную строку с помощью dotnet run
  3. присоединить к запущенному процессу с помощью windbg
  4. из командной строки введите .loadby sos coreclr (это должно определить версию используемого вами ядра .net, но если нет, вы можете использовать .load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos, где 2.05 - это версия используемого вами .netcore
  5. Команды теперь доступны, введя !help
  6. Используйте !dso, чтобы получить дамп стека

В моем случае это точно указывало, где происходило исключение stackoverflow

0 голосов
/ 28 марта 2017

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

У меня было два потока, работающих параллельно, поэтому я остановил запуск одного потока (или вы можете отменить его распараллеливание).

Затем я просмотрел свои функции и добавил функции распечатки, такие как: Как только функция запускается:

Console.WriteLine("<Enter method: {0}", DebuggingHelper.GetCurrentMethod());

Непосредственно перед возвратом функции:

Console.WriteLine(">Exit method: {0}", DebuggingHelper.GetCurrentMethod());

Где GetCurrentMethod определяется как:

[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethod()
{
    StackTrace st = new StackTrace();
    StackFrame sf = st.GetFrame(1);
    return sf.GetMethod().Name;
}

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

Вы также можете добавить контрольную точку, поскольку она проходит через определенные методы.

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

Довольно просто и быстро найти, где это происходит таким образом.

0 голосов
/ 09 ноября 2012

Если у вас есть код и вы можете запустить вашу программу из Visual Studio, она должна прерваться в отладчике (если включены исключения первого шанса) при обнаружении исключения System.StackOverflowException. Оттуда вы можете исследовать стек вызовов и посмотреть, какие вызовы перегружают стек. enter image description here

Я подтвердил, что это работает для Visual Studio 2010 и Visual C # 2010 Express.

0 голосов
/ 19 января 2011

Найдите методы, которые вызывают сами себя (или один метод вызывает другой, и наоборот) и проверяют их. Рекурсия обычно является основным подозрением, когда вы получаете ТАК исключения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...