11

我们一直在试图找出如何通过识别需要内存的宝石并寻找替代方案或解决方案来减少我们的 Rails 应用程序的启动内存占用。

但是我发现 OS X 上的一种行为令人费解。

使用全新生成的 rails 应用程序 ( rails new memoryusage),没有 Gemfile、没有模型、没有数据和没有事务,在启动时rails cOSX 为相应的 ruby​​ 进程显示的内存每次启动时都会变化,从低至 60MB 到高达 65MB,没有明显的模式来解释为什么同一个应用程序每次执行可能需要更少或更多的内存。

我想这在某种程度上与 Ruby 如何分配内存有关,但我并不完全清楚为什么它的内存分配对于相同的代码和没有变量处理会有如此大的变化。

当我们在 Gemfile 中的每个 gem 被需要后尝试计算进程消耗的内存时,我们也会遇到类似的不可预知的行为。我们加载一个 vanilla rails 进程,然后rails c运行一个脚本来解析 Gemfile 并单独要求每个 Gem,记录内存需求前和需求后,我们注意到不仅内存占用量不一致起点,而且我们内存消耗的增量“步骤”变化很大。

我们一次又一次地启动了我们的进程 3 次,并测量了每个 gem 所需的启动内存和增量内存。不仅启动簿内存占用在 60MB 和92MB之间反弹,而且我们在加载每个 gem 时看到的内存跳跃点也不一致——有时加载 SASS 会消耗额外的 5MB,有时不会,有时 active_merchant 会额外要求 10MB,其他则不需要。

                    :    BOOT UP #1            :    BOOT UP #2            :    BOOT UP #3           
gem                 :  increment |      total  :  increment |      total  :  increment |      total
rails               :       0.00 |      59.71  :       0.00 |      92.54  :       0.18 |      67.76
unicorn             :       0.52 |      60.24  :       0.52 |      93.06  :       3.35 |      71.12
haml                :       8.77 |      69.02  :       1.88 |      94.94  :       9.45 |      80.57
haml-rails          :       0.00 |      69.02  :       0.00 |      94.94  :       0.00 |      80.57
sass                :       4.36 |      73.38  :       6.95 |     101.89  :       0.99 |      81.55
mongoid             :       0.00 |      73.38  :       0.00 |     101.89  :       0.00 |      81.55
compass             :      11.56 |      84.93  :       3.23 |     105.12  :       8.41 |      89.96
compass-rails       :       0.00 |      84.93  :       0.08 |     105.20  :       0.00 |      89.96
compass_twitter_bootstrap:       0.00 |      84.93  :       0.00 |     105.20  :       0.00 |      89.96
profanalyzer        :       0.59 |      85.52  :       0.46 |     105.66  :       0.64 |      90.60
simple_form         :       0.34 |      85.87  :       0.35 |     106.01  :       0.00 |      90.60
sorcery             :       0.00 |      85.87  :       0.25 |     106.26  :       1.07 |      91.67
validates_timeliness:       1.47 |      87.34  :       1.82 |     108.07  :       1.62 |      93.29
mongoid_token       :       0.00 |      87.34  :       0.00 |     108.07  :       0.00 |      93.29
nested_form         :       0.00 |      87.34  :       0.00 |     108.07  :       0.01 |      93.30
nokogiri            :       0.86 |      88.20  :       1.16 |     109.24  :       1.37 |      94.67
carmen              :       0.00 |      88.20  :       0.07 |     109.30  :       0.00 |      94.67
carrierwave/mongoid :       2.78 |      90.98  :       0.38 |     109.69  :       0.13 |      94.80
yajl                :       0.04 |      91.02  :       0.04 |     109.73  :       0.04 |      94.84
multi_json          :       0.00 |      91.02  :       0.00 |     109.73  :       0.00 |      94.84
uuid                :       0.00 |      91.03  :       0.00 |     109.73  :       0.41 |      95.25
tilt                :       0.00 |      91.03  :       0.00 |     109.73  :       0.00 |      95.25
dynamic_form        :       0.00 |      91.04  :       0.00 |     109.73  :       0.00 |      95.25
forem               :       0.03 |      91.07  :       0.00 |     109.73  :       0.00 |      95.25
browser             :       0.00 |      91.07  :       0.00 |     109.73  :       0.00 |      95.25
activemerchant      :       2.17 |      93.24  :       1.18 |     110.92  :      10.58 |     105.83
kaminari            :       0.00 |      93.24  :       0.00 |     110.92  :       0.00 |     105.83
merit               :       0.00 |      93.24  :       0.00 |     110.92  :       0.00 |     105.83
memcachier          :       0.00 |      93.24  :       0.00 |     110.92  :       0.00 |     105.83
dalli               :       0.01 |      93.25  :       0.05 |     110.96  :       0.34 |     106.17
bitly               :       2.47 |      95.72  :       9.43 |     120.40  :       1.53 |     107.70
em-synchrony        :       1.00 |      96.72  :       0.18 |     120.57  :       0.55 |     108.24
em-http-request     :       5.56 |     102.28  :       2.15 |     122.72  :       1.40 |     109.64
httparty            :       0.00 |     102.28  :       0.00 |     122.72  :       0.00 |     109.64
rack-block          :       0.00 |     102.28  :       0.00 |     122.72  :       0.00 |     109.64
resque/server       :       1.21 |     103.49  :       1.73 |     124.45  :       1.68 |     111.32
resque_mailer       :       0.00 |     103.49  :       0.00 |     124.45  :       0.00 |     111.32
rack-timeout        :       0.00 |     103.49  :       0.00 |     124.45  :       0.00 |     111.32
chronic             :       1.66 |     105.15  :       0.67 |     125.12  :       0.64 |     111.96
oink                :       0.00 |     105.15  :       0.00 |     125.12  :       0.00 |     111.96
dotenv-rails        :       0.00 |     105.15  :       0.00 |     125.12  :       0.00 |     111.96
jquery-rails        :       0.00 |     105.15  :       0.03 |     125.15  :       0.00 |     111.96
jquery-ui-rails     :       0.00 |     105.15  :       0.00 |     125.15  :       0.00 |     111.96

我很清楚,我缺少一些非常基本的东西,并且不了解内存是如何分配给 Ruby 进程的,但是我很难弄清楚为什么它可能是这种看似随机的。有人有什么想法吗?

4

1 回答 1

1

我要大胆猜测一下,这是由地址空间布局随机化以及与共享库的交互引起的,这些共享库的足迹受到不在测试用例中的运行程序的影响。

从 10.5 开始,OS X 对 ASLR 的支持越来越多,从 10.8 开始,甚至内核都被随机重定位。

在某些情况下,ASLR 可能会导致程序段使用额外的页面,具体取决于偏移量是否会导致跨越页面边界。由于有许多段和许多库,因此这种效果很难预测。

我还想知道(鉴于您所看到的巨大差异)这是否是 OS X 中的一个报告问题。我想知道共享对象的开销是否根据加载顺序被不公平地收取。

您可以通过咨询这个 Stack Overflow 问题进行测试:在 Mac OS X Snow Leopard 中禁用 ASLR。

于 2013-10-03T23:58:22.587 回答