如何增加ruby应用程序的堆栈大小。递归应用程序获取:堆栈级别太深(SystemStackError)

时间:2008-10-28 09:08:58

标签: ruby recursion

在stackoverflow.com上发布堆栈溢出问题,有多么有趣: - )

我正在运行一些递归的Ruby代码,我得到了:"Stack level too deep (SystemStackError)"

(我很确定代码是有效的,我不是在无限的递归死亡螺旋中,但这不是重点)

有没有改变我的Ruby应用程序允许的堆栈深度/大小?

如果这是Ruby中的限制,我不太明白,因为错误说“堆栈级别”,这让我觉得Ruby以某种方式计算堆栈的“级别”,或者它只是意味着堆栈已满了。

我尝试在Vista和Ubuntu下运行此程序,结果相同。 在Ubuntu下我尝试用'ulimit -s'将堆栈大小从8192更改为16000,但这并没有改变任何内容。

编辑: 感谢您的反馈 我确实意识到使用递归函数可能不是最强大的方法。 但这也不是重点。 我只是想知道是否有办法增加堆栈大小..期间。 正如我所提到的,我在运行ruby脚本之前尝试运行ulimit -s 16000 ..没有任何改进..我使用它错了吗?

EDIT2: 事实上,我在代码的边缘情况下进行了无限递归。
当您收到"Stack level too deep"错误时,截断的ruby堆栈跟踪有点误导。
当具有涉及多个函数的递归行为时,您会得到递归次数远低于实际值的印象。在这个示例中,可能会在超过190次调用后崩溃,但实际上是大约15000次调用

tst.rb:8:in `p': stack level too deep (SystemStackError)
        from tst.rb:8:in `bar'
        from tst.rb:12:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
         ... 190 levels...
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:22

-Andreas

6 个答案:

答案 0 :(得分:16)

这个问题及其答案似乎可以追溯到使用C堆栈的Ruby 1.8.x. Ruby 1.9.x及更高版本使用具有自己堆栈的VM。在Ruby 2.0.0及更高版本中,可以通过RUBY_THREAD_VM_STACK_SIZE环境变量控制VM堆栈的大小。

答案 1 :(得分:13)

如果您确定没有无限递归情况,那么您的algorythm可能不适合Ruby以一种重复的方式执行它。将algorythm从递归转换为不同类型的堆栈非常简单,我建议你尝试一下。这是你如何做到的。

def recursive(params)
  if some_conditions(params)
     recursive(update_params(params))
  end
end

recursive(starting_params)

将转变为

stack = [starting_params]
while !stack.empty?
  current_params = stack.delete_at(0)
  if some_conditions(current_params)
    stack << update_params(current_params)
  end
end

答案 2 :(得分:8)

Yukihiro Matsumoto写道here

  

Ruby使用C堆栈,因此您需要   使用ulimit指定限制   堆栈深度。

答案 3 :(得分:6)

Ruby使用C堆栈,因此您的选项包括使用ulimit或使用某些编译器/链接器堆栈大小标志编译Ruby。尾递归尚未实现,Ruby目前对递归的支持并不是那么好。作为酷炫优雅的递归,您可能需要考虑应对语言的限制并以不同的方式编写代码。

答案 4 :(得分:3)

想一想代码是怎么回事。正如其他海报所提到的那样,有可能破解解释器的C代码。然而。结果将是你使用更多的RAM并且不能保证你不会再次烧掉堆栈。

真正好的解决方案是为你想要做的事情提出一个迭代算法。有时候memoisation会有所帮助,有时你发现你没有使用你正在推送堆栈的东西,在这种情况下你可以用可变状态替换递归调用。

如果您不熟悉这类内容,请查看SICP here以获取一些想法......

答案 5 :(得分:3)

只是遇到了同样的问题,很容易在Linux或Mac上修复。正如其他答案所述,Ruby使用系统堆栈设置。您可以通过设置堆栈大小在Mac和Linux上轻松更改此设置。福克斯的例子:

ulimit -s 20000