Ruby的光纤4kB堆栈大小的后果

时间:2012-11-30 03:18:58

标签: ruby fibers stack-size

纤维对我来说是一个相对较新的概念。我知道每个光纤的堆栈大小限制为4kB,我继续读到我应该“小心”这个。这个限制对现实世界的影响究竟是什么?

编辑:

似乎这个4kB限制毕竟不是这样的障碍,它需要光纤本身内的大量局部变量(4,045)才能引发SystemStackError。

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
  eval(s)
end

不是最优雅的代码,但它似乎证明了光纤堆栈的局限性。看起来它只是返回值,局部变量(所有这些变量都包含对堆上对象的引用)和方法调用放在堆栈上。我没有测试从光纤调用的方法中的局部变量等是否是光纤堆栈的一部分。

编辑2:

修改了上面的代码。看来,被调用方法中的变量等成为光纤堆栈的一部分。如果是这种情况,则调用深度(即使没有递归)也可能是一个问题,因为方法本身可能需要更多的空间而不是变量(它们似乎是对堆上对象的透明引用)。 / p>

以下代码在第4,031次迭代时失败,并指示被调用方法中的变量成为光纤堆栈的一部分:

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  m = "def meth\n #{varlist} \n end"
  eval(m)
  fiber = Fiber.new do
    meth
  end
  fiber.resume
end

编辑3:

刚试过在Rubinius 2.0上运行初始代码示例。它的光纤似乎没有4kB的堆栈限制,虽然超过大约3,500次迭代它变得越来越明显变慢,并且在第5,000次迭代时它平均每秒迭代一次。我不知道RBX是否存在限制,因为我在超过5,100次迭代时退出执行。 RBX也使用比MRI 1.9.3多几倍的内存。

JRuby 1.7似乎也没有4kB的光纤堆栈大小,如果光纤的最大堆栈大小,我也不知道。我完成了第一个代码示例的5000次迭代而没有任何问题,尽管可以预料,JVM会咀嚼几百MB的RAM。

2 个答案:

答案 0 :(得分:3)

正如安东在他的回答中所提到的,你在光纤中记忆密集的代码。可能(可能)占用大量内存的东西的例子:

  • 大字符串(即:包含大小合适的HTTP响应的字符串)
  • 递归函数(Stack Level Too Deep!)
  • Streams或stream like objects:对流缓冲区非常小心;如果他们接近或超过4k,你会开始看到一些非常奇怪的行为

答案 1 :(得分:2)

这样做的后果是你必须更加关注光纤代码的内存,因为你可能有内存泄漏。

某些递归函数可能会给您带来问题