ネストされた関数呼び出しが多すぎますか?


15

StackOverflowExceptionについてMSDNから引用:

ネストされたメソッド呼び出しが多すぎるために実行スタックがオーバーフローしたときにスローされる例外。

Too manyここはかなりあいまいです。多すぎると本当に多すぎることをどのようにして知ることができますか?何千もの関数呼び出し?何百万人?私はそれが何らかの形でコンピュータのメモリの量に関係しているに違いないと思いますが、大体正確な大きさのオーダーを考え出すことは可能ですか?

再帰構造と再帰関数呼び出しを多用するプロジェクトを開発しているので、これが心配です。ほんの小さなテスト以上に使用し始めたときに、アプリケーションが失敗するのは望ましくありません。


4
再帰関数を非再帰関数に変換するのは比較的簡単です。データをに貼り付けるだけStack<T>です。
ブライアン

1
「多すぎる」の大きさは、定義するのはあなた次第です。.NETの場合、editbin /stack:WHATEVER-NUMBER-YOU-LIKE yourexefile.exe
SKロジック

回答:


28

再帰構造と再帰関数呼び出しを多用するプロジェクトを開発しているので、これが心配です。ほんの小さなテスト以上に使用し始めたときに、アプリケーションが失敗するのは望ましくありません。

お使いの言語環境サポートのない限り、末尾呼び出しの最適化(とあなたの再帰がある末尾呼び出し)、親指の基本的なルールは次のとおりです。再帰の深さはに基づくアルゴリズムやデータ構造を使用してO(Nログ)、すなわちであることが保証されなければならないディバイド・アンド・征服(ツリー、ほとんどのソートアルゴリズムなど)は問題ありませんが、線形(リンクリスト処理の再帰的実装など)は問題です。


3
+1。非常に良い答えです。私はこのルールを暗黙的に使用していますが、気づいていませんでした。
ジョルジオ

この時代には、形容詞句に値するほぼすべての製品品質のコンパイラがテールコールの最適化をサポートします。
ジョンR.ストローム

1
@ JohnR.Strohmただし、OPは質問.NETにタグを付けているため、現時点では64ビットジッターのみがテールコールの最適化を行います。
マークハード

1
混乱しないように、x86とx64は常にCILの「テール」を尊重します。命令プレフィックス。要約すると、.NETランドでは、F#はテールコールの最適化を完了しますが、C#は完了せず、x64ジッターは「簡単」であれば(依存できません)実行します。blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11/…を
スティーブンスウェンセン

1
確かに、ASP.NETをホストする悪名高いIISの場合のように、単なるO(log n)再帰の深さでさえ、ほとんどすべての再帰(または非再帰的なネストされた呼び出しの長いチェーンでさえも)不可能です。唯一の回避策は、iisバイナリ自体を編集することです。
SKロジック

17

デフォルトでは、CLRは各スレッドのスタックに1 MBを割り当てます(この記事を参照)。したがって、この量を超えるには多くの呼び出しが必要です。これは、各呼び出しがパラメーターやローカル変数などに使用しているスタック上のスペースによって異なります。

StackOverflowException少し正統派ではない場合は、1回の呼び出しでスローすることもできます。

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

残念ながら、この合理的なデフォルトはしばしば違反されます(asp.netなど)。
SKロジック

2

コールキャンベルが指摘したのでメモリサイズをマイケルBorgwardtは指摘テール呼び出しの最適化を、私はそれらをカバーしています。

知っておくべきもう1つのことは、テールコールの最適化が単一の関数に対して行われる複数の織り交ぜられた関数を最適化するために使用できるCPSです。

ここで行ったようにスタックのサイズを増やすことができます。また、64ビットコードは32ビットコードよりも速くスタックを消費することに注意してください。

注目に値するのは、スタックを爆破せずに40時間以上F#interactiveでサンプルの1つを実行したことです。はい、正常に完了するまで継続的に単独で実行されたのは1つの関数呼び出しでした。

また、問題が発生した場所を把握するためにコードカバレッジを行う必要があり、使用できるVSでコードカバレッジがない場合は、TestDriven.NET

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.