【问题标题】:Ruby on Rails memory leak when looping through large number of records; find_each doesn't help循环大量记录时 Ruby on Rails 内存泄漏; find_each 没有帮助
【发布时间】:2011-10-03 21:01:10
【问题描述】:

我有一个 Rails 应用程序,它处理 mysql 数据库中的大量(数百万)条记录。一旦它开始工作,它的内存使用量就会以每秒 50MB 的速度快速增长。使用像 oink 这样的工具,我能够将根本原因缩小到一个循环,该循环遍历数据库中一张大表中的所有记录。

我知道如果我使用像 Person.all.each 这样的东西,所有的记录都会被加载到内存中。但是,如果我切换到 find_each,我仍然会看到相同的内存问题。为了进一步隔离问题,我创建了以下测试控制器,它除了循环记录之外什么都不做。我想 find_each 每次只在内存中保留少量对象,但内存使用量会随着执行而线性增长。

class TestController < ApplicationController
  def memory_test
    Person.find_each do |person|
    end
end

我怀疑这与 ActiveRecord 缓存查询结果有关。但是我检查了我的环境设置,并且在开发中确实将所有与缓存相关的选项都设置为 false(我使用的是 rails 创建的默认设置)。我在网上做了一些搜索,但找不到解决方案。

我正在使用 rails 3.1.0 rc1 和 ruby​​ 1.9.2

谢谢!

【问题讨论】:

  • 我猜ActiveRecord中有一个叫做find_in_batches的函数。可能有助于控制内存爆发。
  • 我也是这么想的,不过,find_each 似乎在幕后使用了find_in_batches。也许每一行都很大并且可以从:batch_size 选项中受益(默认为 1000 行)
  • 需要循环遍历每条记录的代码实际上在做什么?

标签: ruby-on-rails ruby-on-rails-3 activerecord memory-leaks


【解决方案1】:

虽然 ActiveRecord 很好,但它并不是解决所有问题的最佳工具。我建议下拉到您的本机数据库适配器并在该级别完成工作。

【讨论】:

  • 并不是所有的工作都可以在SQL下完成,大部分时候我们需要处理一些复杂的业务逻辑……
【解决方案2】:

我自己能解决这个问题。有两个地方需要改变。

首先,禁用 IdentityMap。在 config/application.rb

config.active_record.identity_map = false

其次,使用uncached来结束循环

class MemoryTestController < ApplicationController
  def go
    ActiveRecord::Base.uncached do
      Person.find_each do |person|
        # whatever operation
      end
    end
  end
end

现在我的内存使用得到控制。希望这对其他人有所帮助。

【讨论】:

  • 每当我遍历大量数据时,是否应该在视图中使用它?
  • 基于文档,identity_map is disabled by default,所以您只需要确保在您当前的配置中它没有设置为 true(至少我会考虑——我会自己测试一下)。
  • 在 heroku 上使用了这个,但在一堆记录上运行一个简单的 *.save 时仍然遇到 R14 内存错误。不值得为了时间而优化(只是一个开发服务器),因此很难证明将其重写为直接 sql 是合理的。我猜还不如从控制台运行。
【解决方案3】:

find_each 在后台调用 find_in_batches,批量大小为 1000。

批处理中的所有记录都将被创建并保留在内存中,只要批处理正在处理。

如果您的记录很大或者它们通过代理集合消耗大量内存(例如,has_many 会在您使用它时缓存其所有项目),您也可以尝试更小的批量大小:

  Person.find_each batch_size: 100 do |person|
    # whatever operation
  end

您也可以尝试定期手动调用GC.start(例如每 300 个项目)

【讨论】:

    猜你喜欢
    • 2010-09-14
    • 2014-05-17
    • 2011-03-28
    • 2011-02-18
    • 1970-01-01
    • 2023-02-18
    • 2011-04-19
    • 1970-01-01
    相关资源
    最近更新 更多