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

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

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

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

但这样写就能无限循环:

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

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

哦,原来是尾递归

是不是每次都进入一个子 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

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