代码之家  ›  专栏  ›  技术社区  ›  Marty

AS3中5287的堆栈限制是可变的还是预定义的?

  •  10
  • Marty  · 技术社区  · 13 年前

    我刚才做了一个测试:

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

    这总是在之后引发StackOverflow错误 5287 电话。

    错误#1023:发生堆栈溢出。

    这个极限变量是(取决于机器规格、环境等)还是某个地方定义的统一值?如果我更改 if 语句小于5287,我没有得到错误。

    3 回复  |  直到 13 年前
        1
  •  2
  •   Vesper    13 年前

    显然这是可变的。由于您实际进行的所有计算都位于堆栈中(反汇编报告代码显示 pushbyte 指令和其他使用堆栈的东西,如非操作数算法),该值只报告堆栈中可以放入多少函数上下文,直到溢出为止。

    我决定运行一些递归阈值测试,基于 this article 巴里斯的评论中提到了这一点。结果相当尴尬。测试环境:FlashDevelop 3.3.4 RTM,Flash播放器调试器10.1.53.64,Flash编译模式:发布。“调试”模式没有从根本上改变数字,也检查了这一点。

    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,加一个int或Number local并不总是减少递归,而且这个值大于8,因为Number变量的原始值需要8个字节,是双精度浮点。
    5. 假设#4是正确的,函数上下文大小的最佳值似乎是172字节,总堆栈大小是912632字节。这在很大程度上证实了我最初的假设,即Flash 10中的堆栈大小实际上是1兆字节。当我尝试在其调试器中打开测试SWF时,Flash 11向我显示了更高的数字,但我没有用它进行广泛的测试。
        2
  •  2
  •   mitim    13 年前

    嗯,这很有趣。我看了一下Bar±给出的链接。毕竟,它看起来可能有“方法复杂性”,但我不确定如何进一步测试它。我正在使用Flash CS5,为Flash Player 10发布,Actionscript 3(当然)。

    原件:

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

    现在向overflow()方法添加一个Math.random()调用:

    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.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
    

    直到我把其中三个锁起来:

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

    看起来来自“group”的两个Math调用“等于”一个Math.pow()调用=b混合Math.pow()和其他东西似乎不会降低值:

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

    然而,链接两个Math.pow():

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

    我可以继续说下去,但我想知道是否有一些模式:

    Results:   5287, 4837, 4457, 4133
    Differences:  450   380   324
    
        3
  •  0
  •   M4tchB0X3r    13 年前

    必须是可变的!刚刚编译了您的样本,在堆栈溢出之前我得到了5274。

    @baris是为mxmlc编译器准备的

    +1用于堆栈溢出问题^^