0

私が書いた次の関数は、再帰は有限ですが、スタックオーバーフローのためにプログラムをクラッシュさせました。

public static void Key(char[] chars, int i, int l, string str) {
    string newStr=null;

    for(int j=0; j<l; j++)
        newStr+=chars[i/(int)Math.Pow(68, j)%68];

    if(newStr==str)
        return;

    Key(chars, ++i, l, newStr);
}

これらのパラメーターを使用してメソッドを呼び出すと、すべてうまくいきます。

Key(chars, 0, 4, "aaaa");

しかし、より多くの呼び出しになると、StackOverflowException. したがって、問題は、メソッドが有限であるにもかかわらず、メソッドのジョブが完了する前にコールスタックがいっぱいになることだと思います。それで、それについていくつか質問があります:

  1. 関数がスタックから明確にならない理由は、もはや必要ではなく、値を返さないからです。

  2. もしそうなら、スタックを手動でクリアする方法はありますか? クラスを試してみましたStackTraceが、この場合は無力です。

4

4 に答える 4

1

したがって、コードがそのベース ケースに到達するかどうかに関係なく、本番環境でコードがスタック オーバーフロー例外を受け取ることはありません。

たとえば、これでスタック オーバーフローが発生するはずですよね?

private static void Main(string[] args)
{
    RecursorKey(0);
}

public static int RecursorKey(int val)
{
    return RecursorKey(val ++);
}

実際、.NET 4 を使用していてデバッグを行っておらず、バイナリがリリースとしてコンパイルされている場合は、そうではありません。

これは、clr がいわゆる末尾再帰を行うのに十分なほど賢いためです。末尾再帰はどこにでも適用できるわけではありませんが、あなたの場合はそうであり、正確な問題を簡単に再現できました。あなたの場合、関数を呼び出すたびに、別のスタック フレームがスタックにプッシュされるため、アルゴリズムが理論的にはある時点で終了しても、オーバーフローが発生します。

問題を解決するために、最適化を有効にする方法を次に示します

ただし、 Jon Skeetがテール コールの最適化に依存しないことを推奨していることを指摘しておく必要があります。ジョンは頭がいいので、彼の言うことに耳を傾けます。コードが大きなスタック深度に遭遇する場合は、再帰なしでコードを書き直してみてください。

于 2013-04-05T19:06:49.330 に答える