2012-08-02 2 views
5

미니 덤프에 따르면 특정 파일이 재귀 적 파생 파서에서 스택 오버플로를 일으키는 상황이 발생했습니다. 불행히도 나는이 문제를 재현하기 위해이를 수행하는 파일의 예 (클라이언트가 기밀 유지 문제를 가지고 있음)에 손을 대지 못해서 잠시 실제 문제를 진단하는 데 약간의 어려움을 겪습니다.작업자 스레드에서 스택 오버플로를 방지하거나이를 복구 할 수 있습니까?

분명히 파서가주의를 기울여야하지만 지금 당장 최우선 과제는 프로그램을 계속 실행하는 것입니다. 임시 방편으로 전체 프로그램을 중단시키지 않으려면 어떻게해야합니까?

첫 번째 선택은 오버플로가 발생하기 전에 파서를 정상적으로 중단 할 수 있도록 스택의 공간이 부족할 것으로 예상하는 방법을 찾는 것입니다. 파일을 구문 분석하지 못하면 허용되는 옵션입니다. 두 번째 방법은 오류를 잡아 로그에 기록한 다음 나머지 데이터로 계속 진행하는 것입니다.

Parallel.ForEach() 루프에서 구문 분석이 발생합니다. 그것이 도움이된다면 나는 다른 접근법을 위해 그것을 바꿀 용의가있다.

편집 : 현재 스레드의 스택 크기와 스택 포인터의 위치를 ​​얻을 수 있다면 정말 킬러가 될 것입니다. 이것이 가능한가?

EDIT 2 : 결국 누군가의 샘플 파일을 추출하고 디버거에서 오류를 잡아낼 수있었습니다. 그것은 우리에게 속한 코드가 아닙니다. 예외는 어딘가에 HtmlAgilityPack에 있습니다. 그래서 저는 완전히 다른 압정을 찾아야 할 것 같습니다.

+0

정확히 스택 오버 플로우를 일으키는 원인이 명확하지 않으므로 (paralellism이 재귀를 유발할 수는 없으므로) 도움이 될지 확실하지 않지만'ParallelOptions.MaxDegreeOfParallelism'을 사용하여 동시 호출의 양을 제한하려 했습니까? – Jcl

+0

하나의 옵션은 구문 분석의 현재 "깊이"를 추적하는 것이고 너무 높으면 보석을 해제하는 것입니다. – dlev

+0

@dlev 자세한 내용은 알고 싶습니다. .NET 문서에 나와 있듯이 스택 프레임과 호출 스택의 크기가 다양하기 때문에 적절한 최대 깊이를 선택하는 방법은 무엇입니까? –

답변

3

스택의 데스크톱 CLR에는 기본적으로 1MB 제한이 있지만 사용자는 can increase it입니다.

continuation passing style을 사용하면 스택 대신 힙을 사용할 수 있습니다.

C# 5.0에는이 프로세스를 자동화하는 컴파일러에서 제공하는 비동기 메커니즘이 있습니다. 나는 최신 빌드로 이것을 시도하지 않았다. Alex가 언급했듯이 C#에서 꼬리 - 호출 최적화에 대한 지원은 없으며 이것은 문제를 파싱하기 위해 F #을 채택 할만큼 충분히 큰 이유 일 수 있습니다. 여기에 some material on lexing and parsing with F#. YMMV가 있습니다. this article.

presence of bad inputs에서 프로그램을 안정화하려면 그래프주기 감지가 필요합니다.

더 많은 정보를 수집하는 방법으로, 호출 스택의 깊이를 추적하는 누적 기 정수를 찾아 낼 수 있습니다. 이 함수는 상기 호출 스택에 의해 소비되는 메모리로 직접 변환하지는 않지만 일반적인 아이디어를 제공합니다. 예를 들어, 해당 숫자가 사용자가 구성 할 수 있거나 미리 정의 된 임계 값보다 클 경우 자신의 예외를 포착 할 수 있습니다.

public void Recursive(int acc) 
{ 
    if (acc > myLimit) 
     throw new MyOverflowException(acc); 

    Recursive(acc+1); 
} 

다음 호출 사이트 : 요청으로

try { Recursive(0); } catch (MyOverflowException) { /* handle it*/ } 

, 나는 인해 SOE에 충돌 this very topic.

+1

조금 자세하게 좋을 것입니다. –

+0

@ GregC 이것은 장기적인 솔루션으로 생각하고 있습니다. 그러나 지금 당장 나는 임시 방편을 찾고 있는데, 그것은 다소 큰 리팩터가 될 것입니다. –

+1

나는 연속 전달 스타일의 예제를 제공하고 스택을 덜 사용하는 방법을 보여줄 수도 있습니다. –

0

스레드에 에릭 Lippert의에 의해 멋진 블로그에 당신을 연결합니다 전체 과정을 중단시키고 그것에 대해 할 수있는 일이별로 없습니다.

복구 방법으로 파서를 별도의 프로세스로 시작하고 IPC 메커니즘을 설정하여 자식과 통신 할 수 있습니다. 그렇게하면 자식 프로세스가 주 프로세스에 영향을주지 않고 자유롭게 죽을 수 있습니다.

관련 문제