C# поймать исключение переполнения стека
Я получил рекурсивный вызов метода, который выдает исключение переполнения стека. Первый вызов окружен блоком try catch, но исключение не перехвачено.
Поведение переполнения стека ведет себя особым образом? Могу ли я поймать / обработать правильно исключение?
NB: если уместно:
исключение не выбрасывается в основной поток
объект, в котором код генерирует исключение, загружается вручную Assembly.LoadFrom(...).CreateInstance(...)
10 ответов
Начиная с 2.0, исключение Stackru может быть обнаружено только при следующих обстоятельствах.
- CLR запускается в размещенной среде*, где хост специально разрешает обработку исключений Stackru
- Исключение переполнения стека генерируется пользовательским кодом, а не из-за реальной ситуации переполнения стека ( ссылка)
*"размещенная среда", как в "мой код размещает CLR, и я настраиваю параметры CLR", а не "мой код работает на виртуальном хостинге"
Правильный путь - это исправить переполнение, но....
Вы можете дать себе больший стек:-
using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();
Вы можете использовать свойство System.Diagnostics.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 на StackruException s:
В предыдущих версиях.NET Framework ваше приложение могло перехватывать объект StackruException (например, для восстановления после неограниченной рекурсии). Однако такая практика в настоящее время не рекомендуется, поскольку требуется значительный дополнительный код, чтобы надежно перехватить исключение переполнения стека и продолжить выполнение программы.
Начиная с версии.NET Framework 2.0, объект StackruException не может быть перехвачен блоком try-catch, и соответствующий процесс завершается по умолчанию. Следовательно, пользователям рекомендуется писать свой код для обнаружения и предотвращения переполнения стека. Например, если ваше приложение зависит от рекурсии, используйте счетчик или условие состояния для завершения рекурсивного цикла. Обратите внимание, что приложение, в котором размещается общеязыковая среда выполнения (CLR), может указать, что CLR выгружает домен приложения, в котором возникает исключение переполнения стека, и позволяет соответствующему процессу продолжаться. Для получения дополнительной информации см. Интерфейс ICLRPolicyManager и Хостинг общеязыковой среды выполнения.
Как уже сказали несколько пользователей, вы не можете поймать исключение. Однако, если вы изо всех сил пытаетесь выяснить, где это происходит, вы можете настроить Visual Studio так, чтобы он ломался при его запуске.
Для этого вам необходимо открыть "Настройки исключений" в меню "Отладка". В более старых версиях Visual Studio это было в "Отладка" - "Исключения"; в более новых версиях это в "Отладка" - "Windows" - "Настройки исключения".
После того, как вы откроете настройки, разверните "Исключения общеязыкового языка", разверните "Система", прокрутите вниз и выберите "System.StackruException". Затем вы можете посмотреть на стек вызовов и найти повторяющийся шаблон вызовов. Это должно дать вам представление о том, где искать исправления кода, вызывающего переполнение стека.
Как упоминалось выше несколько раз, невозможно отловить исключение StackruException, которое было вызвано Системой из-за поврежденного состояния процесса. Но есть способ заметить исключение как событие:
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.stackruexception.aspx
Вы не можете, как объясняет большинство постов, позвольте мне добавить еще одну область:
На многих веб-сайтах вы найдете людей, которые говорят, что способ избежать этого - использовать другой домен приложений, поэтому в этом случае домен будет выгружен. Это абсолютно неправильно (если только вы не размещаете свой CLR), так как поведение CLR по умолчанию вызовет событие KillProcess, в результате чего ваш AppDomain будет отключен.
Ты не можешь CLR не позволит вам. Переполнение стека является фатальной ошибкой и не может быть восстановлено из.
Это невозможно и по уважительной причине (например, подумайте обо всех этих уловах (Исключение){}).
Если вы хотите продолжить выполнение после переполнения стека, запустите опасный код в другом домене приложений. Политики CLR могут быть настроены так, чтобы прервать текущий домен приложений при переполнении, не затрагивая исходный домен.
Вы можете проверить стек перед выполнением метода с помощью метода RuntimeHelpers.EnsureSufficientExecutionStack msdn.
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
try
{
Recursion();
}
catch (InsufficientExecutionStackException e)
{
}
}
static void Recursion()
{
RuntimeHelpers.EnsureSufficientExecutionStack();
Recursion();
}
}