加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby – 将超过130798个对象推入数组时的SystemStackError

发布时间:2020-12-17 03:49:32 所属栏目:百科 来源:网络整理
导读:我试图理解为什么在数组中推送许多(在我的情况下为130798)对象会返回SystemStackError. big = Array.new(130797,1)[].push(*big) false= falsebigger = Array.new(130798,1)[].push(*bigger) false= SystemStackError: stack level too deep from (irb):104
我试图理解为什么在数组中推送许多(在我的情况下为130798)对象会返回SystemStackError.

big = Array.new(130797,1)
[].push(*big) && false
=> false

bigger = Array.new(130798,1)
[].push(*bigger) && false
=> SystemStackError: stack level too deep
     from (irb):104
     from /Users/julien/.rbenv/versions/2.2.0/bin/irb:11:in `<main>'

我能够在MRI 1.9.3和2.2.0上重现它,而Rubinius(2.5.2)没有出现错误.

我知道这是由于Array在MRI中实现的方式,但不太明白为什么会引发SystemStackError.

解决方法

Ruby的错误消息(“堆栈级别太深”)在这里不准确 – Ruby真正说的是“我用尽了堆栈内存”,这通常是由无限递归引起的,但在这种情况下,是由你传递引起的比Ruby分配更多的参数来处理.

Ruby 2.0的最大堆栈大小由RUBY_T??HREAD_VM_STACK_SIZE控制(在2.0之前,这由C限制控制,通过ulimit设置).传递给方法的每个参数都被推送到线程的堆栈中;如果你将更多的参数压入堆栈而不是RUBY_T??HREAD_VM_STACK_SIZE有足够的空间,你将得到一个SystemStackError.你可以从IRB看到这个限制:

RubyVM::DEFAULT_PARAMS[:thread_vm_stack_size]
=> 1048576

默认情况下,每个线程都有1MB的堆栈可供使用. Ruby Fixnum大8字节,在我的系统上,我溢出130808个参数,或者分配1046464个字节,剩下2112个字节分配给其余的调用堆栈.通过使用splat运算符(*),您将“获取130798个Fixnums的列表,并将其扩展为130798个参数,以便在堆栈中传递”;你根本没有足够的堆栈内存来保存它们.

如果需要,可以在调用Ruby时增加RUBY_T??HREAD_VM_STACK_SIZE:

$RUBY_THREAD_VM_STACK_SIZE=2097152 irb
> [].push(*Array.new(150808,1)); nil
 => nil

这将增加你可以传递的参数数量.但是,这也意味着每个线程将分配两倍的堆栈,这可能是不可取的.您还应该注意,Fibers有一个单独的堆栈分配设置,通常要小得多,因为Fibers的设计是轻量级和一次性的.

你很少需要在堆栈上传递那么多数据;通常,如果需要将大量数据传递给方法,则应将对象作为参数传递(即,在堆栈上,例如哈希或数组),其存储在堆上分配,因此您的堆栈即使您的堆使用量以兆字节为单位,也会以字节为单位测量使用情况.也就是说,您可以将非常大的数组传递给您的方法(它可以在堆上保存数十亿字节数而不会出现问题),然后您将在方法中迭代该数组.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读