Scala递归深度差异和下面的StackOverflowError允许深度

时间:2015-11-25 19:39:34

标签: scala recursion jvm stack-overflow

编写以下程序是为了检查Scala中的递归深度可以深入到我的机器上。我假设它主要取决于分配给该程序的堆栈大小。但是,在计算了递归的最大深度(在出现时捕获异常)并尝试模拟此深度的递归后,我得到了奇数输出。

/usr/lib/jvm/java-8-oracle/bin/java

Recursion depth on this system is 7166.
sumArrayRec = 25672195

Process finished with exit code 0

结果因程序的执行而异。

其中一个是理想的输出:

/usr/lib/jvm/java-8-oracle/bin/java

Recursion depth on this system is 8129.
Exception in thread "main" java.lang.StackOverflowError
    at RecursionTest$.goFrom$1(lab44.scala:6)
    at RecursionTest$.goFrom$1(lab44.scala:6)
    at RecursionTest$.goFrom$1(lab44.scala:6)
    (...)
    at RecursionTest$.goFrom$1(lab44.scala:6)
    at RecursionTest$.goFrom$1(lab44.scala:6)

Process finished with exit code 1

然而,我得到的第二个可能的输出表示错误:

println("sumArrayRec = " + sumArrayRec((0 until recDepth).toArray))

我没有观察到他们的任何依赖或关系,我只是第一次获得,其他时间获得第二次

所有这些都引导我提出以下问题:

  1. 为什么我会收到错误以及导致错误的原因?
  2. 这是堆栈溢出错误,如果是......
  3. 为什么程序运行时堆栈的大小会同时发生变化?它甚至可能吗?
  4. 当我将println("sumArrayRec = " + sumArrayRec((0 until recDepth - 5000).toArray))更改为 <Command Name="ShutDown"> <ListenFor>Shut down</ListenFor> <Navigate/> </Command> ,更不用说,行为保持不变。

1 个答案:

答案 0 :(得分:1)

  1. 由于导致堆栈溢出而导致堆栈溢出
  2. 最大堆栈没有变化,JVM设置了这个。您的两个方法recurseTestsumArrayRec将不同的金额推送到堆栈。 recurseTest 基本在每次调用时为堆栈添加2个整数,而sumArrayRec正在添加3个整数,因为您有elms(i)调用,可能更多添加/ ifelse (更多说明)。由于JVM正在处理所有这些问题,因此很难说清楚它的目的是将这一点与您需要知道的内容混淆。此外,谁知道JVM在幕后做了哪些优化,这些优化可以极大地影响从每个方法调用创建的堆栈大小。在多次运行中,由于系统时序等原因,您可以获得不同的堆栈深度,也许jvm会在程序运行的短时间内优化,也许它不会被激活,它可能是非确定性的这种情况。如果您事先运行了一些预热代码,可能会使您的测试更具确定性,那么任何优化都将会或不会发生。
  3. 你应该考虑使用类似JMH的东西进行测试,这将有助于确定性。

    附注:您也可以使用-Xss2M手动更改堆栈大小,这对于SBT的使用很常见。