【问题标题】:Tracing memory leak in Ruby on Rails 3 / Postgres / Apache Passenger application在 Ruby on Rails 3 / Postgres / Apache Passenger 应用程序中跟踪内存泄漏
【发布时间】:2011-07-19 04:24:45
【问题描述】:

你好,

我们最近将一个应用程序更新到 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、文档、源代码 cmets 和路径名。 (为什么?)

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

  1. 我创建了一个全新的 Rails 3 应用程序,其中包含单个资源和控制器以及 SQLite3 数据库。 内存使用量从 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”。 内存使用量增长较慢,但在请求后仍不会停止增长
  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

【问题讨论】:

  • 您的服务器使用什么?乘客或 Rails 内置服务器?
  • 我试过Passenger 3.0.3和WEBrick,都表现出相同的行为。
  • 我遇到了同样的问题,所以我删除了 AASM,但泄漏并没有消失。您如何确定导致泄漏的宝石?
  • @asoules,一般来说,“分而治之”。如果您怀疑某个插件,请删除一半插件并进行测试。如果错误仍然存​​在,则您知道错误在哪一半。继续直到找到罪魁祸首。
  • 如果你为你的问题写了一个答案,那就太好了。

标签: ruby-on-rails-3 postgresql memory-leaks rspec-rails


【解决方案1】:

【讨论】:

  • 谢谢,第一个链接将我指向 ObjectSpace。我可以打印一个统计表,如图所示。似乎每次请求时,Rails 都会将我的整个应用程序的附加副本重新加载到内存中。但为什么呢?
  • 不确定。也许你可以在这个top-secret Rails Guide! (Rails 3.1)找到它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 2011-03-17
  • 2023-03-29
  • 2015-07-16
  • 2021-01-22
  • 1970-01-01
  • 2011-04-19
相关资源
最近更新 更多