9

当我运行它然后在 OSX 活动监视器中观察我的 ruby​​ 进程的内存消耗时,内存以大约 3 MB/s 的速度增加。

如果我删除事务,它的内存消耗大约会减半,但内存占用量仍在增加。我的生产应用程序有一个问题,Heroku 由于其内存消耗而终止了该进程。

有没有办法以不会增加内存的方式执行以下操作?如果我注释掉该.save行,那没关系,但这当然不是解决方案。

ActiveRecord::Base.transaction do
  10000000.times do |time|
    puts "---- #{time} ----"
    a = Activity.new(:name => "#{time} Activity")
    a.save!(:validate => false)
    a = nil
  end
end

我正在使用delayed_job.

4

2 回答 2

5

a = nil行是不必要的,您可以将其删除。

每次循环时都会创建很多对象 - 两个字符串、两个哈希值和一个 Activity 对象,所以我并不惊讶您遇到高内存使用情况,尤其是当您循环 1000 万次时!似乎没有更高效的方式来编写此代码。

我能想到的减少内存使用的唯一方法是每x次迭代手动启动垃圾收集器。Ruby 的 GC 可能不够积极。但是,您不希望每次迭代都调用它,因为这会从根本上减慢您的代码。也许您可以将每 100 次迭代作为起点,然后从那里开始。你必须分析和测试什么是最有效的。

GC的文档在这里

于 2012-05-05T14:28:27.620 回答
1

我知道这是一个古老的问题,但我必须提出另一种激进的方法:

ActiveRecord::Base.transaction do
  10000000.times do |time|
    puts "---- #{time} ----"
    sql = <<SQL
INSERT INTO activities ("name") VALUES ("#{time}")
SQL
    Activity.connection.execute(sql)
  end
end

关键是,如果插入如此简单,并且您已经跳过任何 ActiveModel 验证,那么首先没有理由实例化一个 activerecord 对象。通常它不会受到伤害,但由于在这种情况下它会伤害你,我认为你会用这种方式使用更少的内存。

于 2013-12-31T01:11:22.097 回答