这样的代码是会栈溢出的:
b = proc do
print '.'
b[]
end
b[]
但这样写就能无限循环:
b = proc do
Fiber.new do
print '.'
b[]
end.resume
end
b[]
为什么呢?留待读者思考。。。
占内存还行,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
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
试了几次都挂掉。。
@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 的可用进程空间基本没有了。