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

纤维对我来说是一个相对较新的概念。 我知道每个光纤的堆栈大小限制为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 

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

编辑2:

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

以下代码在第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来咀嚼。

其结果是您必须更加关注光纤代码的内存,因为您可能有内存泄漏。

一些递归函数可能会给你带来问题

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

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