15

你好,

我们最近将应用程序更新到 Rails 3.0.4(在线开发服务器上的 3.0.5)。从 2.3.10 到 3.0.4 的大部分更改是由于过时或过时的插件和 gem 造成的,并且可以相对容易地解决。但有一件事让我很生气:

在开发模式下,每个 Web 请求都会导致服务器进程分配比以前多 50-60 MB的内存。这个内存在请求之后没有被释放,至少不是全部。在 10-20 个请求之后,每个 Ruby 实例消耗超过500 MB 的 RAM,而我们之前的 Rails 2.3.10 实例很少超过 200 MB。

这使得我们无法运行我们的 1300 次测试,因为在测试结束之前开发机的 4GB RAM 已被填满。它只发生在开发模式下cache_classes = false。如果我将 cache_classes 切换为 true,Rails 实例将消耗大约 200MB 的内存,然后停留在那里。但是,在测试期间,即使 cache_classes = true,内存使用量也会增加。

我查询了 ObjectSpace,发现每个请求都会创建大约 3500 个新 Proc、多达 50'000 个新字符串以及 3000 个新哈希和数组,但未释放。这些字符串(转储时)包含我的整个源代码,包括插件和 gem、文档、源代码注释和路径名。(为什么?)

为了找到造成这种情况的原因,我尝试了以下方法:(每次更改后,我都使用ab -n 50.)

  1. 我创建了一个新的 Rails 3 应用程序,它只有一个资源和控制器以及 SQLite3 DB。内存使用量从 60 MB 开始,一直低于 80 MB
  2. 我将“sqlite3”更改为“pg”,并将新的 Rails 3 应用程序指向我现有的 Postgres DB。内存使用量从 110 MB 开始,并没有超过 130 MB。(附带问题:为什么 Postgres gem 使用比 SQLite3 gem 更多的内存?)
  3. 我将我的Gemfile 和 Gemfile.lock从损坏的 Rails3 应用程序复制到基本应用程序并运行bundle install没有变化,无论发出多少请求,内存都保持在 115MB 左右。
  4. 我在损坏的 Rails3 应用程序中创建了一个空的“def FooController; def foo; render :text => 'foo' end; end”。内存使用量增长较慢,但在 requests 之后仍然没有停止增长
  5. 我删除了除 FooController 路由之外的所有路由。没有变化
  6. 我禁用了所有宝石,但以下除外:pg, rails, aasm, will_paginate, geokit-rails3, koala, omniauth, paperclip. 没有变化
  7. 我禁用了 ApplicationController 中的每个 before_filter 和 after_filter 以及 environment.rb 中的每个非必需项include。我还将 boot.rb、environment.rb 和 application.rb 与我的基本 Rails 3 应用程序同步,除了五个相对简单的观察者,在 /lib 和 filter_parameters 中自动加载文件。没有变化。每个新请求仍会额外消耗 10-50 MB 的 RAM。

如果您知道这里出了什么问题,以及内存泄漏可能在哪里,我将非常感谢任何帮助。我在 OS X Snow Leopard 上运行 Rails 3.0.4,在 Debian Lenny 上运行 Rails 3.0.5,以及

谢谢!

接近了:

我已经删除了每个插件、每个 gem、每个扩展以及我没有亲自编写的所有内容,因此我的应用程序基本上是赤裸裸的。特别是,我删除了这些插件:acts_as_list, acts_as_tree, asset_packager, forgot_password, fudge_form, fudge_scaffold, paperclippolymorph, query_trace, rails_upgrade, repeated_auto_complete-0.1.0, role_requirement, to_select, validates_url, and ym4r_gm.

现在我的应用程序 - 只有上面的 FooController 仍然有效!- 以 65MB 启动并且永远不会超过 75MB 的 RAM,即使在使用ab -n 1000 -c1(使用 ApacheBench 向 /foo 发出 1000 个 HTTP 请求)敲击它之后也是如此。不幸的是,如果没有插件,这也是唯一有效的 URI。

经过一番挖掘,似乎是 Restful Authentication 和 Acts As State Machine (AASM) 插件之间的组合导致了内存泄漏。另请参阅https://github.com/Satish/restful-authentication/issues#issue/11。我还不确定为什么,只是在我的准系统项目中执行“包含 AASM”并不会单独导致 RAM 使用量增长。

我会进一步调查。

发现罪魁祸首

它是 AASM。在 Rails 3 中,它似乎泄漏了 AASM::xxx 对象实例。看

找到第二个罪魁祸首

rspec 中还有另一个内存泄漏。这使得我的测试几乎无法忍受,即使在删除 AASM 之后也是如此,因为两个并行运行的 rspec 任务(使用https://github.com/grosser/parallel_tests)最后占用了将近 3GB 的内存。请参阅https://github.com/rspec/rspec-core/issues/#issue/321

4