Ruby 关于今天 ruby tuesday 的 quiz ....

night_song · 2012年03月13日 · 最后由 hooopo 回复于 2012年03月14日 · 3287 次阅读

这样的代码是会栈溢出的:

b = proc do
  print '.'
  b[]
end
b[]

但这样写就能无限循环:

b = proc do
  Fiber.new do
    print '.'
    b[]
  end.resume
end
b[]

为什么呢? 留待读者思考 。。。

共收到 15 条回复

神奇!

哦,原来是尾递归

是不是每次都进入一个子fiber,挺有趣的,跑了下第二种,老牛车基本被拖死。 应该有个内存的上限吧~

内存持续稳定增加,不久的将来就会out of memory..

#5楼 @Saito 据观察ruby进程占8M以后就挂掉

`resume': mprotect failed (FiberError)
    from f.rb:2:in `block in <main>'
    from f.rb:4:in `[]'
    from f.rb:4:in `block (2 levels) in <main>'

占内存还行,61300个纤程占了500M左右的内存,平均每个10k左右 不过创建速度比较差,而且越来越慢,前20000个用了2s,前70000个竟然用了18s

另外 @hooopo 说的8M以后挂掉是怎么回事?我没遇到,大家对比一下ulimit?

$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 30620 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 300000 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 30620 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited

#8楼 @fsword

ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited


试了几次都挂掉。。

#9楼 @hooopo 看了一下,也就这个不一样了

open files (-n) 300000

看来不是内存的问题,是句柄不够了,提醒一下搞系统优化的同学,首先把这个参数改了吧

#10楼 @fsword 不是8M,是8%.看错了。。 这个应该是我的电脑32位 ubuntu10.04的默认参数

PS,ns同学的上面的代码溢出时间和stack size参数有关,下面的代码的溢出时间和open files参数有关....

@fsword 这也不属于尾递归优化,内存一直增长,吃掉可用的Ruby进程空间,就会out of memory 而crash。

它的原理是利用了fiber都有一个独立的stack(4KB),从而避开了Ruby VM的stack,所以可以这样夸张的递归下去。话说回来,这样递归的进入fiber,就会为每个fiber所自带的stack付出内存代价。递归级数太深的话,也很危险,毕竟太吃内存了。

@hooopo 我认为和open files 无关。我机器的open files 才256。我认为跟你的机器是32bit,进程空间小有关。因为crash是因为调用mprotect这个系统调用失败,ruby抛了一个异常。应该是你的Ruby的可用进程空间基本没有了。

#12楼 @skandhas 嗯,是我说错了,这里没有利用尾递归优化,不过我之前的测试看到,每个Fiber的成本是10K而不是4K,难道是32位和64位不同?

另外,又试了一下,确实和 open files 无关,我调低了参数也是一样不会crash,我是64位,不知道 @hooopo 是不是32位,不过我还是不能理解这个和进程空间有关,这么4K/Fiber的加上去,怎么会撑爆进程空间(用户空间至少有2G)呢?

#13楼 @fsword 4KB只是fiber自带的stack的大小。 用户空间可以使用的并没有想象的多,里面有代码段,数据段,还有各种so或dll映射的空间,系统预留的内存映射文件的空间,Stack的空间等等等~ 除去这些,Heap的空间就剩下一部分了。

我的机器跑这个脚本过很快就过1G内存。至于@hooopo 的机器的错误,我在这里也是推测 :)

#13楼 @fsword #14楼 @skandhas 我的是32位系统 并且每次运行都是输出32000左右个点以后就crash

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册