중첩 된 함수 호출이 너무 많습니까?


15

StackOverflowException에 대해 MSDN 에서 인용했습니다 .

중첩 된 메소드 호출이 너무 많아 실행 스택이 오버 플로우 될 때 발생하는 예외입니다.

Too many여기는 꽤 모호합니다. 너무 많은 시간이 너무 많은 시간을 어떻게 알 수 있습니까? 수천 개의 함수 호출? 수백만? 나는 그것이 어떤 방식으로 컴퓨터의 메모리 양과 관련이 있어야한다고 가정하지만 대략 정확한 크기의 순서를 제시 할 수 있습니까?

나는 재귀 구조와 재귀 함수 호출을 많이 사용하는 프로젝트를 개발하고 있기 때문에 이것에 대해 걱정하고 있습니다. 작은 테스트 이상으로 응용 프로그램을 사용할 때 응용 프로그램이 실패하는 것을 원하지 않습니다.


4
재귀 함수를 비 재귀 함수로 변환하는 것은 비교적 쉽습니다. 에 데이터를 붙이기 만하면 Stack<T>됩니다.
Brian

1
"너무 많은"크기는 전적으로 사용자에게 달려 있습니다. .NET의 경우을 사용하십시오 editbin /stack:WHATEVER-NUMBER-YOU-LIKE yourexefile.exe.
SK-logic

답변:


28

나는 재귀 구조와 재귀 함수 호출을 많이 사용하는 프로젝트를 개발하고 있기 때문에 이것에 대해 걱정하고 있습니다. 작은 테스트 이상으로 응용 프로그램을 사용할 때 응용 프로그램이 실패하는 것을 원하지 않습니다.

언어 환경에서 테일 콜 최적화를 지원하지 않는 한 (귀하의 재귀 테일 콜인 경우) 기본 규칙은 다음과 같습니다. 재귀 깊이는 O (log n) 여야합니다. 예를 들어 나누기 및 정복 (나무, 대부분의 정렬 알고리즘 등)은 괜찮지 만 선형 (연관된 목록 처리의 반복 구현과 같은) 것은 아닙니다.


3
+1. 아주 좋은 대답, 나는이 규칙을 암시 적으로 사용했지만 그것을 알지 못했습니다.
Giorgio

요즘에는 형용사에 적합한 프로덕션 품질 컴파일러가 테일 콜 최적화를 지원할 것입니다.
John R. Strohm

1
@ JohnR.Strohm 그러나 OP는 질문에 .NET 태그를 지정 했으므로 AFAIK는 현재 64 비트 지터 만 테일 콜 최적화를 수행합니다.
Mark Hurd

1
혼란이 없기 때문에 x86과 x64는 항상 CIL "꼬리"를 존중합니다. 명령 접두사. 요약하자면, .NET 랜드에서 F #은 테일 콜 최적화를 완료하고 C #은 수행하지 않으며 x64 지터는 "쉬운"(의존 할 수없는) 경우 수행합니다. blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11/…
Stephen Swensen 2013 년

1
사실이지만 ASP.NET을 호스팅하는 악명 높은 IIS와 같이 일부 경우에는 O (log n) 재귀 깊이조차도 한심한, 정당화되지 않고, 웃을 수있는 작은 스택 깊이 제한으로 인해 실패 할 수 있습니다. 이로 인해 거의 모든 재귀가 발생합니다 (또는 비 재귀 중첩 호출의 긴 체인조차도 불가능합니다. 유일한 방법은 iis 바이너리 자체를 editbin하는 것입니다.
SK-logic

17

기본적으로 CLR은 각 스레드의 스택에 1MB를 할당합니다 ( 이 기사 참조 ). 그러나이 금액을 초과하려면 많은 통화가 필요합니다. 각 호출이 매개 변수 및 로컬 변수와 같은 것들에 사용하는 스택의 공간에 따라 다릅니다.

StackOverflowException약간의 정통성을 기꺼이 원한다면 단일 통화로 던질 수도 있습니다.

private static unsafe void BlowUpTheStack()
{
    var x = stackalloc byte[1000000000];
    Console.WriteLine("Oh no, I've blown up the stack!");
}

불행하게도,이 합리적인 불이행은 종종 위반됩니다 (예 : asp.net).
SK-logic

2

Cole Campbell메모리 크기를 언급 하고 Michael Borgwardt꼬리 호출 최적화를 언급 했기 때문에 이에 대해서는 다루지 않을 것입니다.

알아 두어야 할 또 다른 사항은 꼬리 호출 최적화가 단일 기능을위한 여러 개의 직조 기능을 최적화하는 데 사용할 수있는 CPS 입니다.

여기 에서 한 것처럼 스택의 크기를 늘릴 수 있으며 64 비트 코드는 32 비트 코드보다 빠르게 스택을 사용합니다.

우리는 스택을 불지 않고 40 시간 이상 동안 F # 대화 형에서 예제 중 하나를 실행했습니다. 예, 성공적인 완료를 위해 지속적으로 자체 실행되는 함수 호출이었습니다.

또한 문제가 발생하는 위치를 파악하기 위해 코드 범위를 수행해야하고 VS 코드 범위가없는 경우 TestDriven.NET을 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.