10

私はちょうど今テストを実行しました:

function overflow(stack:int = 0):void
{
    if(stack < 5290)
    {
        trace(stack);
        overflow(stack + 1);
    }
}

overflow();

これは、呼び出し後に常にStackOverflowエラーをスローし5287ます。

エラー#1023:スタックオーバーフローが発生しました。

この制限は可変ですか(マシンの仕様、環境などによって異なります)、それともフラットな値がどこかで定義されていますか?ifステートメントを5287未満に変更しても、エラーは発生しません。

4

3 に答える 3

2

明らかに可変です。実際に実行するすべての計算はスタックに配置されるため (逆アセンブリ レポート コードはpushbyte、オペランド以外の算術演算としてスタックで動作する命令やその他のものを表示します)、この値は、オーバーフローするまでスタックに配置できる関数コンテキストの数のみを報告します。

baris のコメントで参照されたこの記事に基づいて、再帰しきい値のいくつかのテストを実行することにしました。結果はかなり恥ずかしかったです。テスト環境: FlashDevelop 3.3.4 RTM、Flash Player デバッガー 10.1.53.64、フラッシュ コンパイル モード: リリース。「デバッグ」モードでは基本的に数値が変更されませんでした。それも確認しました。

Locals number     Iterations (static int)       Iterations (Math.random())   
0                 5306                          
1                 4864                          4856
2                 4850                          4471
3                 4474                          4149
4                 4153                          3870
5                 3871                          3868
6                 3869                          3621
7                 3620                          3404
8                 3403                          3217
9                 3210                          3214
10                3214                          3042
11                3042                          3045
10 mixed          3042     1 value was assigned Math.random() and 9 - static int
10 advancedRandom 2890     1 value was assigned a custom random with 1 parameter

これらの値はすべて、後続の実行間で 10 の範囲内で変化することに注意してください。「static int」と「Math.random()」は、再帰的に呼び出される関数内のローカルに割り当てられるものの指定です。ただし、これにより、次のことが想定されます。

  1. 関数呼び出しを再帰関数に含めると、関数コンテキストが追加されます
  2. ローカルを追加しても再帰制限が常に減少するとは限らないため、ローカルのメモリはそのタイプとともに 8 バイトを超えるチャンクで割り当てられます。
  3. 特定の関数に複数の呼び出しを追加しても、関数コンテキストにメモリが追加されない
  4. 「メモリ チャンク」の長さはおそらく 16 バイトです。この値は 2^N であり、1 つの int または Number ローカルを追加しても再帰が常に減少するとは限らず、Number 変数の生の値が 8 を超えるためです。倍精度浮動小数点である 8 バイト。
  5. #4 が正しいと仮定すると、関数コンテキスト サイズの最適な値は 172 バイトで、合計スタック サイズは 912632 バイトです。これは、スタック サイズが実際には Flash 10 で 1 メガバイトであるという私の最初の仮定をほぼ裏付けています。Flash 11 のデバッガーでテスト SWF を開こうとすると、少し大きい数値が示されましたが、それを使用して詳細なテストを行ったわけではありません。
于 2013-03-04T07:55:35.017 に答える
2

うーん、これは面白い。Barışがくれたリンクを見てみました。結局、「メソッドの複雑さ」に関係しているように思えますが、それをさらにテストする方法がわかりません。私はFlash CS5を使用しており、Flash Player 10、Actionscript 3(もちろん)用に公開しています。

オリジナル:

function overflow(stack:int = 0):void {
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// gives 5287

ここで、1 つの Math.random() 呼び出しを overflow() メソッドに追加します。

function overflow(stack:int = 0):void {
    Math.random();
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// gives 4837

複数の Math.random() 呼び出しを追加しても違いはありません。また、ローカル変数に格納したり、overflow() メソッドに別のパラメーターを追加して、ランダムに生成された値を「運ぶ」こともできません。

function overflow(stack:int = 0):void {
    Math.random();
    Math.random();
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// still gives 4837

この時点で、次のようなさまざまな Math 呼び出しを試しました。

// just the change to that 1 line:
Math.pow() // gives 4457
Math.random(), Math.sqrt(), Math.tan(), Math.log() // gives 4837

興味深いことに、Math クラスに何を渡すかは問題ではないようですが、一定のままです。

Math.sqrt(5) vs Math.sqrt(Math.random()) // gives 4837
Math.tan(5) vs Math.tan(Math.random()) // gives 4837
Math.pow(5, 7) vs Math.pow(Math.random(), Math.random()) // 4457

私がそれらのうちの3つを連鎖するまで:

Math.tan(Math.log(Math.random())); // gives 4457

その「グループ」からの 2 つの Math 呼び出しは、1 つの Math.pow() 呼び出しと「等しい」ように見えますか? =b Math.pow() と何か他のものを混ぜても、値は減少しないようです:

Math.pow(Math.random(), Math.random()); // gives 4457

ただし、2 つの Math.pow() をチェーンすると、次のようになります。

Math.pow(Math.pow(Math.random(), Math.random()), Math.random()); // 4133

私は何度も続けることができますが、いくつかのパターンがあるのだろうか:

Results:   5287, 4837, 4457, 4133
Differences:  450   380   324
于 2013-03-04T06:30:50.097 に答える
0

可変でなければなりません!サンプルをコンパイルしたところ、スタック オーバーフローの前に 5274 になりました。

@baris mxmlc コンパイラ用

スタックオーバーフローの質問に+1 ^^

于 2013-03-04T01:00:45.783 に答える