C# поймать исключение переполнения стека
Я получил рекурсивный вызов methode, который вызывает исключение переполнения стека. Первый звонок окружен блоком try catch, но исключение не поймано.
исключение переполнения стека ведет себя особым образом ? Могу ли я правильно поймать / обработать исключение ?
NB: при необходимости:
исключение не выбрасывается в основной поток
объект, где код бросает исключение вручную загружается сборкой.LoadFrom(...).CreateInstance(...)
9 ответов:
начиная с 2.0 исключение StackOverflow может быть поймано только в следующих случаях.
- среда CLR выполняется в размещенной среде, где хост специально позволяет обрабатывать исключения StackOverflow
- исключение 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 на StackOverflowException s:
в предыдущих версиях .NET Рамки, ваше приложение может поймать объект StackOverflowException (например, для восстановления неограниченная рекурсия). Однако, что практика в настоящее время не рекомендуется потому что значительный дополнительный код необходимое для надежного перехвата стека исключение переполнения и продолжить выполнение программы.
начиная с .NET Рамки версия 2.0, исключение StackOverflowException объект не может быть пойман с помощью try-catch блок и соответствующий процесс прекращена по умолчанию. Следовательно, пользователям рекомендуется написать свой код обнаружение и предотвращение стека переполнение. Например, если ваш применение зависит от рекурсии, использования счетчик или условие состояния для завершения рекурсивного цикла. Отмечать это приложение, которое размещает общеязыковая среда выполнения (CLR) может укажите, что среда CLR выгружает домен приложения, в котором находится стек возникает исключение переполнения и пусть соответствующий процесс продолжается. Для дополнительные сведения см. В разделе Интерфейс ICLRPolicyManager и Размещения среды CLR.
Как уже сказали несколько пользователей, вы не можете поймать исключение. Однако, если вы изо всех сил пытаетесь выяснить, где это происходит, вы можете настроить visual studio на разрыв, когда он будет брошен.
для этого вам нужно открыть Настройки исключений из меню "отладка". В более старых версиях Visual Studio это происходит в "Debug" - "Exceptions"; в более новых версиях это происходит в "Debug" - "Windows" - "Exception Settings".
после открытия настроек разверните узел "Исключения общеязыковой среды выполнения", разверните "система", прокрутите вниз и проверьте " система.StackOverflowException'. Затем вы можете посмотреть на стек вызовов и искать повторения звонков. Это должно дать вам представление о том, где искать, чтобы исправить код, который вызывает переполнение стека.
Как упоминалось выше несколько раз, невозможно поймать исключение StackOverflowException, которое было вызвано системой из-за поврежденного состояния процесса. Но есть способ заметить исключение как событие:
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspxначиная с .NET Framework версии 4, это событие не вызывается для исключений, которые повреждают состояние процесса, например переполнения стека или нарушения прав доступа, если только обработчик событий не критичен с точки зрения безопасности и не имеет атрибута HandleProcessCorruptedStateExceptionsattribute.
тем не менее ваше приложение завершится после выхода из event-функции (очень грязный обходной путь, чтобы перезапустить приложение в рамках этого события ха-ха, не сделал этого и никогда не будет делать). Но это достаточно хорошо для ведения журнала!
в .NET Framework версий 1.0 и 1.1 необработанное исключение, которое возникает в поток, отличный от основного потока приложения, перехватывается средой выполнения и поэтому не приводит к завершению работы приложения. Таким образом, событие UnhandledException может быть вызвано без завершения приложения. Начиная с версии 2.0 платформы .NET Framework, эта резервная остановка для необработанных исключений в дочерних потоках была удалена, поскольку совокупный эффект таких тихих сбоев включал снижение производительности, поврежденные данные и блокировки, все из которых были трудно отлаживать. Дополнительные сведения, включая список случаев, в которых среда выполнения не завершается, см. В разделе исключения в управляемых потоках.
да от переполнения стека CLR 2.0 считается невосстановимой ситуацией. Таким образом, среда выполнения по-прежнему завершает процесс.
подробности см. В документации http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx
вы не можете. CLR не позволит вам. Переполнение стека является фатальной ошибкой и не может быть восстановлено.
вы не можете, как большинство сообщений объясняют, позвольте мне добавить еще одну область:
на многих сайтах вы найдете люди говорят, что способ избежать этого-использовать другой домен, так что если это произойдет, домен будет выгружен. Это абсолютно неверно (если вы не размещаете свою среду CLR), поскольку поведение среды CLR по умолчанию вызовет событие KillProcess, сбив ваш домен приложений по умолчанию.
Это невозможно, и по уважительной причине (например, подумайте обо всех тех catch(Exception){} вокруг).
Если вы хотите продолжить выполнение после переполнения стека, запустите опасный код в другом домене приложения. Политики среды CLR могут быть настроены на завершение текущего домена AppDomain при переполнении, не затрагивая исходный домен.
Comments