2009-10-21 15 views
91

스택 오버플로 예외가 발생하는 메서드에 대한 재귀 호출이 발생했습니다. 첫 번째 호출은 try catch 블록으로 둘러싸여 있지만 예외는 발견되지 않습니다.C# 스택 오버플로 예외가 발생했습니다.

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

NB : 해당하는 경우 :

  • 예외가 메인 스레드

  • 코드가 예외를 던지고 객체에 슬로우되지 않는 수동 (Assembly.LoadFrom이에 의해로드됩니다 ...) .CreateInstance (...)

+3

@RichardOD, 내가 버그이기 때문에 버그를 수정해야합니다. 그러나 문제는 다른 방식으로 나타날 수 있으며 처리 할 수 ​​없게됩니다. – Toto

+7

동의 함, 스택 오버플로는 잡히지 않아서 잡힐 수없는 심각한 오류입니다. 대신 깨진 코드를 수정하십시오. –

+9

@ 리차드 코드 : 예 : 재귀 적 파서인데 호스트 시스템이 실제로 요구하는 것 이상의 깊이에 대한 인위적인 제한을 두지 않는다. 어떻게해야 하나? 내 druthers 있다면, 거기에 약간의 스택 공간이 남아있는 동안 해고 될 명시 적으로 잡힐 수 StackCritical 예외가있을 것입니다; 그것은 실제로 던져 질 때까지 스스로를 무력하게 할 것이고, 스택 공간의 안전한 양이 남아있을 때까지 잡힐 수 없다. – supercat

답변

88

2.0부터는 다음과 같은 경우에만 StackOverflow 예외를 캐치 할 수 있습니다.

  1. CLR에 유래 예외가 실제 스택 오버 플로우 상황으로 인해
  2. 유래 예외는 사용자 코드에 의해 발생되고,하지 처리하는 호스트 특별히 허용 호스팅 환경에서 실행되고 (Reference)
+17

관련 scebario에서 잡힐 수없는 경우 StackoverflowException 객체가있는 이유는 무엇입니까? – Manu

+8

@Manu 적어도 두 가지 이유가 있습니다. 1) 그것은 1.1에서 잡힐 수 있고 목적이있다. 2) CLR을 호스팅하고 있어도 여전히 유효한 예외 유형이므로 – JaredPar

+2

이 잡힐 수있는 경우에도 잡힐 수 있습니다 ... 발생한 문제를 설명하는 Windows 이벤트에 전체 스택 추적이 기본적으로 포함되어 있지 않은 이유는 무엇입니까? –

6

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

StackOverflowException들에 MSDN 페이지에서 문서 http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx

+0

CLR 2.0에서 'StackOverflowException'은 기본적으로 프로세스를 종료합니다. –

+0

아니요. OOM을 잡을 수 있으며 경우에 따라 그렇게 할 수도 있습니다. 나는 실이 사라짐으로써 당신이 의미하는 바를 모른다. 스레드에 처리되지 않은 예외가있는 경우 CLR은 프로세스를 종료합니다. 스레드가 메소드를 완료하면 정리됩니다. –

33

를 참조하십시오 닷넷 프레임 워크의 이전 버전에서

, 응용 프로그램 수 잡을있는 StackOverflowException 개체 (대한 예를 들어, 무한 재귀를 에서 복구 할 수 있습니다. 그러나 연습은 현재 인데, 스택을 안정적으로 catch하고 프로그램 실행을 계속하려면 중요한 추가 코드가 이어야하므로 실망입니다. 닷넷 프레임 워크 버전 2.0을 시작으로

는하는있는 StackOverflowException 객체는 시도 - 캐치 블록에 의해 체포하고 해당 프로세스는 기본적으로 종료 입니다 수 없습니다. 결과적으로 사용자는 코드를 작성하여 스택을 감지하고 방지합니다. 오버플로. 예를 들어 응용 프로그램이 재귀에 종속되어있는 경우 카운터 또는 상태 조건을 으로 지정하면 재귀 루프가 종료됩니다. 를 참고 는 CLR이 스택 오버 플로우 예외가 발생 응용 프로그램 도메인을 언로드 것을 지정하고 해당 프로세스를 계속 할 수있는 공용 언어 런타임 (CLR)을 호스팅하는 응용 프로그램입니다. 에 대한 자세한 내용은 ICLRPolicyManager Interface 및 공용 언어 런타임 호스팅을 참조하십시오.

5

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

+0

그렇다면 캐치 가능한 대신 단위 테스트 러너를 충돌시키는 대신이 예외에 대해 단위 테스트를 실패하게 만드시겠습니까? – BrainSlugs83

+0

@ BrainSlugs83. 그건 바보 같은 생각이야. StackOverflowException으로 인해 코드가 실패한 경우 테스트하는 이유는 무엇입니까? CLR이 변경되어 더 깊은 스택을 처리 할 수 ​​있다면 어떻게됩니까? 이미 깊이 중첩 된 스택이있는 어딘가에서 유닛 테스트 함수를 호출하면 어떻게됩니까? 그것은 테스트 할 수없는 무언가처럼 보입니다. 수동으로 던지려는 경우 작업에 대한 더 나은 예외를 선택하십시오. –

3

좋은 이유 (주위에 모든 catch (Exception) {}에 대해 생각하십시오).

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

+1

"catch"문은 실제로 문제가되지 않습니다. catch 문이 실행될 때까지는 시스템이 두 개의 많은 스택 공간을 사용하려고 시도한 결과를 롤백했기 때문입니다.스택 오버 플로우 예외를 포착하는 것은 위험 할 수밖에 없습니다. 이러한 예외가 잡히지 않는 이유는 스택을 사용하는 모든 코드에 오버 헤드가 발생하지 않더라도 일부 추가 오버 헤드를 추가해야 할 수 있기 때문입니다. – supercat

+3

어느 시점에서 그 진술은 잘 생각되지 않습니다. Stackoverflow를 잡을 수 없다면 프로덕션 환경에서 어디서 일어 났는지 결코 알 수 없을 것입니다. – Offler

20

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

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

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

+0

VS 2015의 디버그 - 예외는 어디에 있습니까? – FrenkyB

+0

디버그 - Windows - 예외 설정 – Simon

38

올바른 방법은 오버 플로우를 수정하는 것입니다,하지만 ....

당신은 자신에게 더 큰 스택을 제공 할 수 있습니다 : -

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

은 그냥 치즈를 잡을 수있어. ;)

게시물의 대부분이 설명 될 때 당신은 나에게 또 다른 영역 추가 할 수 없습니다
+34

'치즈'는 구체적이지 않습니다. 나는 새로운 치즈 예외 ("Gouda")를 던지기를 갈 것입니다. " –

+12

@ C.Evenhuis 고다가 예외적 인 치즈라는 것은 의심의 여지가 없지만 RollingCheeseException ("Double Gloucester ")은 http : // www. cheese-rolling.co.uk/ –

+2

롤, 1) 고정을 할 수없는 이유는 어디에서 발생하는지 모르는 경우가 많기 때문입니다. 2) Stacksize를 늘리면 ** 무한 ** 재귀와 함께 쓸모가 없습니다. 3) 스택 검사 올바른 위치에있는 것은 – Firo

5

: 당신은 사람들이 방법은 다른 응용 프로그램 도메인을 사용하고이를 방지 할 수 있다는 말을 찾을 수 많은 웹 사이트에

을이 그렇다면 도메인이 언로드됩니다. CLR의 기본 동작이 KillProcess 이벤트를 발생시켜 기본 AppDomain을 가져 오는 것처럼 절대적으로 잘못되었습니다 (CLR을 호스팅하지 않는 한).

7

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

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

.NET Framework 버전 4로 시작하는이 이벤트는 예외 발생되지 않도록 스택 오버 플로우 또는 프로세스의 손상 상태, 이벤트 처리기가 보안 상 중요하지 않고 HandleProcessCorruptedStateExceptionsAttribute 특성이없는 경우 액세스 위반이 발생할 수 있습니다.

그럼에도 불구하고 이벤트 기능을 종료 한 후 종료됩니다 응용 프로그램 (아주 더러운 해결 방법은,이 이벤트 하하 내에서 응용 프로그램을 다시 시작 이렇게 havn't는 것이 었습니다 할 것 않음). 그러나 로깅에 충분합니다!

.NET Framework 버전 1.0 및 1.1에서 주 응용 프로그램 스레드 이외의 스레드에서 발생하는 처리되지 않은 예외는 런타임에서 캐치되어 응용 프로그램이 종료되지 않습니다. 따라서 응용 프로그램을 종료하지 않고 UnhandledException 이벤트를 발생시킬 수 있습니다. .NET Framework 버전 2.0부터는 자식 스레드의 처리되지 않은 예외에 대한 이러한 백스톱이 제거되었는데, 그 이유는 이러한 자동 실패의 누적 효과에는 성능 저하, 손상된 데이터 및 잠금 장치 등이 포함되어 있었기 때문입니다. 런타임이 종료되지 않는 경우의 목록을 포함하여 자세한 내용은 관리되는 스레드의 예외를 참조하십시오.

+0

와우. 이것은 더 많은 upvotes가 있어야합니다! –

관련 문제