这是重现问题的示例代码.
# test.rb
n = 100000
res = {}
1.upto(n).to_a.inject(res) do |r, i|
r[i] = {}
end
def f(x)
x.each_value { |v| f(v) }
end
f(res)
Run Code Online (Sandbox Code Playgroud)
使用Docker Hub提供的Docker镜像运行此代码.
有什么区别?
(对不起,我的英语不好.)
这是一个补充说明.
我知道示例代码导致SystemStackError.我编写了示例代码以导致SystemStackError.
我想知道"水平"差异的原因.
在这种情况下,堆栈级别为137.
% docker container run -v (pwd):/mnt/my --rm -it ruby:2.5.0-alpine3.7 ruby -v /mnt/my/test.rb
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
Traceback (most recent call last):
149: from /mnt/my/test.rb:11:in `<main>'
148: from /mnt/my/test.rb:8:in `f'
147: from /mnt/my/test.rb:8:in `each_value'
146: from /mnt/my/test.rb:8:in `block in f'
145: from /mnt/my/test.rb:8:in `f'
144: from /mnt/my/test.rb:8:in `each_value'
143: from /mnt/my/test.rb:8:in `block in f'
142: from /mnt/my/test.rb:8:in `f'
... 137 levels...
4: from /mnt/my/test.rb:8:in `f'
3: from /mnt/my/test.rb:8:in `each_value'
2: from /mnt/my/test.rb:8:in `block in f'
1: from /mnt/my/test.rb:8:in `f'
/mnt/my/test.rb:8:in `each_value': stack level too deep (SystemStackError)
Run Code Online (Sandbox Code Playgroud)
但简单的情况下,堆栈级别为13092.
% docker container run --rm -it ruby:2.5.0-alpine3.7 ruby -v -e 'def f; f; end; f'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
Traceback (most recent call last):
13104: from -e:1:in `<main>'
13103: from -e:1:in `f'
13102: from -e:1:in `f'
13101: from -e:1:in `f'
13100: from -e:1:in `f'
13099: from -e:1:in `f'
13098: from -e:1:in `f'
13097: from -e:1:in `f'
... 13092 levels...
4: from -e:1:in `f'
3: from -e:1:in `f'
2: from -e:1:in `f'
1: from -e:1:in `f'
-e:1:in `f': stack level too deep (SystemStackError)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,堆栈级别为10067.与上述情况有很大不同.
% docker container run -v (pwd):/mnt/my --rm -it ruby:2.4.3-alpine3.7 ruby -v /mnt/my/test.rb
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-linux-musl]
/mnt/my/test.rb:8:in `each_value': stack level too deep (SystemStackError)
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
... 10067 levels...
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:11:in `<main>'
Run Code Online (Sandbox Code Playgroud)
我显示了差异 Dockerfile的输出.
--- 2.4/alpine3.7/Dockerfile 2017-12-28 20:34:43.000000000 +0900
+++ 2.5/alpine3.7/Dockerfile 2017-12-28 20:34:43.000000000 +0900
@@ -7,9 +7,9 @@
echo 'update: --no-document'; \
} >> /usr/local/etc/gemrc
-ENV RUBY_MAJOR 2.4
-ENV RUBY_VERSION 2.4.3
-ENV RUBY_DOWNLOAD_SHA256 23677d40bf3b7621ba64593c978df40b1e026d8653c74a0599f0ead78ed92b51
+ENV RUBY_MAJOR 2.5
+ENV RUBY_VERSION 2.5.0
+ENV RUBY_DOWNLOAD_SHA256 1da0afed833a0dab94075221a615c14487b05d0c407f991c8080d576d985b49b
ENV RUBYGEMS_VERSION 2.7.4
ENV BUNDLER_VERSION 1.16.1
Run Code Online (Sandbox Code Playgroud)
这意味着使用相同的Alpine Linux.只是Ruby是不同的.
在这种情况下,堆栈级别为9866.此案例使用Ruby 2.5.0,但它运行在Debian(而不是Alpine).
% docker container run -v (pwd):/mnt/my --rm -it ruby:2.5.0-stretch ruby -v /mnt/my/test.rb
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
Traceback (most recent call last):
9878: from /mnt/my/test.rb:11:in `<main>'
9877: from /mnt/my/test.rb:8:in `f'
9876: from /mnt/my/test.rb:8:in `each_value'
9875: from /mnt/my/test.rb:8:in `block in f'
9874: from /mnt/my/test.rb:8:in `f'
9873: from /mnt/my/test.rb:8:in `each_value'
9872: from /mnt/my/test.rb:8:in `block in f'
9871: from /mnt/my/test.rb:8:in `f'
... 9866 levels...
4: from /mnt/my/test.rb:8:in `f'
3: from /mnt/my/test.rb:8:in `each_value'
2: from /mnt/my/test.rb:8:in `block in f'
1: from /mnt/my/test.rb:8:in `f'
/mnt/my/test.rb:8:in `each_value': stack level too deep (SystemStackError)
Run Code Online (Sandbox Code Playgroud)
我们在一些边缘案例中也看到了这一点。我们已经确认,操作系统和 Ruby 堆栈大小在所有情况下都是相同的。(alpine 2.4.3、alpine 2.5.0 以及在 MacOS 上本地运行 2.5.0)
迄今为止我们能发现的唯一区别是 Alpine 2.5.0 镜像是基于 Alpine 3.7 构建的,后者使用 LibreSSL 构建 Ruby。2.4.3 镜像是基于 Alpine 3.4 构建的,后者仍然使用 OpenSSL。我们针对 OpenSSL 的本地 2.5.0 构建不会显示这种“短”堆栈长度。
| 归档时间: |
|
| 查看次数: |
505 次 |
| 最近记录: |