101

스택 오버플로 예외를 throw하는 methode에 대한 재귀 호출이 있습니다. 첫 번째 호출은 try catch 블록으로 둘러싸여 있지만 예외는 발견되지 않습니다.

스택 오버플로 예외가 특별한 방식으로 동작합니까? 예외를 올바르게 캐치 / 처리 할 수 있습니까?

주의 사항 : 관련성이있는 경우 :

  • 주 스레드에서 예외가 throw되지 않습니다.

  • 코드에서 예외를 throw하는 개체는 Assembly.LoadFrom (...)에 의해 수동으로로드됩니다. CreateInstance (...)


  • @ RichardOD, 내가 버그이기 때문에 나는 버그를 수정했다. 그러나 문제는 다른 방식으로 나타날 수 있으며이를 처리 할 수 있습니다. - Toto
  • 동의합니다. 스택 오버플로는 심각한 오류이므로 잡힐 수 없습니다.~붙 잡히다. 대신 깨진 코드를 수정하십시오. - Ian Kemp
  • @ 리차드 드 : 예를 들면. 재귀 적 파서인데 호스트 시스템이 실제로 요구하는 것 이상의 깊이에 대한 인위적인 제한을 두지 않는다. 어떻게해야 하나? 내 druthers 있다면, 거기에 약간의 스택 공간이 남아있는 동안 해고 될 명시 적으로 잡힐 수 StackCritical 예외가있을 것입니다; 그것은 실제로 던져 질 때까지 스스로를 무력하게 할 것이고, 스택 공간의 안전한 양이 남아있을 때까지 잡힐 수 없다. - supercat
  • 이 질문은 유용합니다 - 스택 오버 플로우 예외가 발생하면 유닛 테스트를 실패하고 싶습니다. 그러나 NUnit은 테스트를 "무시 된" 카테고리가 아니라 다른 카테고리와 마찬가지로 실패 할 수도 있습니다.이를 잡아서Assert.Fail대신. 그래서 진지하게 - 우리는 어떻게 이것에 관해 가야합니까? - BrainSlugs83

9 답변


94

StackOverflow Exception은 2.0부터는 다음과 같은 상황에서만 잡힐 수 있습니다.

  1. 호스트에서 특히 StackOverflow 예외를 처리 할 수있는 호스트 환경에서 CLR이 실행 중입니다.
  2. stackoverflow 예외는 실제 스택 오버플로 상황이 아닌 사용자 코드에 의해 발생합니다.참고)


  • 관련 scebario에 걸리지 않으면 StackoverflowException 객체가 존재하는 이유는 무엇입니까? - Manu
  • 적어도 두 가지 이유 때문에 @Manu. 1) 그것은 1.1에서 잡힐 수 있고 목적이있다. 2) CLR을 호스팅하는 경우에도 여전히 잡힐 수 있으므로 여전히 유효한 예외 유형입니다. - JaredPar
  • 걸릴 수없는 경우 ... 발생한 문제를 설명하는 Windows 이벤트에 기본적으로 전체 스택 추적이 포함되지 않는 이유는 무엇입니까? - user645280
  • 호스트 된 환경에서 StackOverflowExceptions을 처리하는 방법은 무엇입니까? 내가 호스팅 된 환경을 실행하고 전체 응용 프로그램 풀을 파괴하는 정확한 문제가 있기 때문에 내가 묻는 이유가 있습니다. 나는 스레드를 중단하고 오히려 위로 되돌릴 수 있으며, 그런 다음 오류를 기록하고 모든 apppool의 스레드를 죽이지 않고 계속 진행할 수 있습니다. - Brain2000
  • Starting with 2.0 ..., 난 골동품, 무엇 때문에 그걸 잡지 못하고 어떻게 가능 한가요?1.1(당신이 귀하의 의견에 언급)? - M.kazem Akhgary

42

올바른 방법은 오버플로를 수정하는 것이지만 ....

자신에게 더 큰 스택을 줄 수 있습니다.

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

System.Diagnostics.StackTrace FrameCount 속성을 사용하면 사용한 프레임을 셀 수 있고 프레임 제한에 도달하면 사용자가 예외를 throw 할 수 있습니다.

또는 남아있는 스택의 크기를 계산할 수 있으며 임계 값 이하로 떨어지는 경우 자체 예외를 throw합니다.

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();
    }
}

그냥 치즈를 잡으세요. ;)


  • Cheese구체적이지 않다. 나는 가야 해.throw new CheeseException("Gouda"); - C.Evenhuis
  • @ C.Evenhuis 고다는 예외적 인 치즈라는 의심의 여지가 없지만 RollingCheeseException ( "Double Gloucester")가 실제로 볼 수있는 예외적 인 치즈입니다.cheese-rolling.co.uk - user159335
  • 롤업, 1) 고정을 할 수없는 이유는 그것을 잡지 않으면 어떤 일이 발생했는지 종종 알지 못하기 때문입니다. 2) Stacksize를 늘리는 것은 쓸모가 없습니다.끝이없는재귀 andm 3) 올바른 위치에 스택을 확인하는 것은 첫 번째와 같습니다 - Firo
  • 하지만 나는 락토스를 용납하지 않는다. - redoc

35

에 MSDN 페이지에서StackOverflowException에스:

이전 버전의 .NET   프레임 워크, 애플리케이션   StackOverflowException 객체 잡기   (예 :   무한 재귀). 그러나, 그   연습은 현재 낙담하고있다.   중요한 추가 코드가   스택을 안정적으로 잡아야한다.   예외를 오버 플로우하고 계속하기   프로그램 실행.

.NET Framework로 시작하기   버전 2.0, StackOverflowException   try-catch로 객체를 포착 할 수 없다.   블록 및 해당 프로세스가   기본적으로 종료되었습니다. 따라서,   사용자는 코드 작성을 권장합니다.   스택 감지 및 방지   과다. 예를 들어,   응용 프로그램은 재귀, 사용에 의존합니다.   카운터 또는 상태 조건을   재귀 루프를 종료합니다. 노트   호스팅하는 응용 프로그램   공용 언어 런타임 (CLR)   CLR이 언로드되도록 지정   스택이있는 응용 프로그램 도메인   오버플로 예외가 발생하고   해당 프로세스가 계속됩니다. 에 대한   자세한 내용은 다음을 참조하십시오.   ICLRPolicyManager 인터페이스 및   공용 언어 런타임 호스팅


20

여러 사용자가 이미 말했듯이 예외를 잡을 수는 없습니다. 그러나 어디에서 일어나는지 알아 내려고 애 쓰고 있다면 비주얼 스튜디오가 튕겨 지도록 구성 할 수 있습니다.

이를 수행하려면 '디버그'메뉴에서 예외 설정을 열어야합니다. Visual Studio의 이전 버전에서는 'Debug'- 'Exceptions'에 있습니다. 최신 버전에서는 'Debug'- 'Windows'- 'Exception Settings'에 있습니다.

설정이 열리면 '공용 언어 런타임 예외'를 확장하고 '시스템'을 확장 한 다음 아래로 스크롤하여 'System.StackOverflowException'을 선택하십시오. 그런 다음 호출 스택을보고 반복되는 호출 패턴을 찾을 수 있습니다. 스택 오버플로를 야기하는 코드를 어디에 수정해야하는지에 대한 아이디어를 얻을 수 있습니다.


  • 어디 디버그 - VS 2015에서 예외가 무엇입니까? - FrenkyB
  • 디버그 - Windows - 예외 설정 - Simon

12

위에서 몇 번 언급했듯이 프로세스 상태가 손상되어 시스템에서 발생한 StackOverflowException을 catch 할 수 없습니다. 그러나 예외를 이벤트로 인식하는 방법이 있습니다.

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부터는 자식 스레드의 처리되지 않은 예외에 대한 이러한 백스톱이 제거되었는데, 그 이유는 이러한 자동 실패의 누적 효과에는 성능 저하, 손상된 데이터 및 잠금 장치 등이 포함되어 있었기 때문입니다. 런타임이 종료되지 않는 경우의 목록을 포함하여 자세한 내용은 관리되는 스레드의 예외를 참조하십시오.


  • 와우. 이것은 더 많은 upvotes가 있어야합니다! - Arsen Zahray

6

예, CLR 2.0 스택 오버플로는 복구 할 수없는 상황으로 간주됩니다. 따라서 런타임은 여전히 프로세스를 종료합니다.

자세한 내용은 설명서를 참조하십시오.http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx


  • CLR 2.0부터StackOverflowException기본적으로 프로세스를 종료합니다. - Brian Rasmussen
  • 아닙니다. 당신은 OOM을 붙잡을 수 있으며 어떤 경우에는 그렇게 할 수 있습니다. 스레드가 사라지는 것이 무엇을 의미하는지 알 수 없습니다. 스레드에 처리되지 않은 예외가있는 경우 CLR은 프로세스를 종료합니다. 스레드가 메소드를 완료하면 정리됩니다. - Brian Rasmussen

5

당신은 할 수 없습니다. CLR은 당신을 내버려 두지 않을 것입니다. 스택 오버플로는 치명적인 오류이므로 복구 할 수 없습니다.


  • 그렇다면 단위 테스트 러너를 대신 잡을 수있는 대신에이 예외에 대한 단위 테스트를 실패하게 만드는 방법은 무엇입니까? - BrainSlugs83
  • @ BrainSlugs83. 그건 바보 같은 생각인데, 당신은 모르겠다. StackOverflowException으로 인해 코드가 실패한 경우 테스트하는 이유는 무엇입니까? CLR이 변경되어 더 깊은 스택을 처리 할 수 있다면 어떻게됩니까? 이미 깊이 중첩 된 스택이있는 어딘가에서 유닛 테스트 함수를 호출하면 어떻게됩니까? 테스트 할 수없는 것 같습니다. 수동으로 던지려는 경우 작업에 대한 더 나은 예외를 선택하십시오. - Matthew Scharley

5

대부분의 게시물이 설명하는 것처럼 다른 영역을 추가 할 수 없습니다.

많은 웹 사이트에서이 문제를 피하는 방법이 다른 AppDomain을 사용하고 있다고 말하는 사람들이 있습니다. 이렇게되면 도메인이 언로드됩니다. CLR의 기본 동작이 KillProcess 이벤트를 발생시켜 기본 AppDomain을 가져 오는 것처럼 절대적으로 잘못되었습니다 (CLR을 호스팅하지 않는 한).


3

그것은 불가능하고 좋은 이유가 있습니다. (하나는 주위에있는 모든 catch (Exception) {}에 대해 생각하십시오.)

스택 오버플로 후에도 계속 실행하려면 다른 AppDomain에서 위험한 코드를 실행하십시오. 원래 도메인에 영향을주지 않고 오버플로시 현재 AppDomain을 종료하도록 CLR 정책을 설정할 수 있습니다.


  • "캐치" catch 문이 실행될 때까지는 시스템이 두 개의 많은 스택 공간을 사용하려고 시도한 결과를 롤백 했으므로 명령문은 실제로 문제가되지 않습니다. 스택 오버플로 예외를 잡을 이유가 없어야합니다. 이러한 예외가 잡힐 수없는 이유는 이들을 안전하게 잡을 수 있도록 허용하기 위해 추가 오버 헤드를 추가해야한다는 것입니다.모든오버플로가 발생하지 않더라도 스택을 사용하는 코드 - supercat
  • 어떤 점에서 그 성명은 잘 생각하지 않습니다. Stackoverflow를 잡을 수 없다면 프로덕션 환경에서 어디서 일어 났는지 결코 알 수 없을 것입니다. - Offler

연결된 질문


관련된 질문

최근 질문