在关系上建立记录时,内存膨胀

时间:2012-05-08 22:18:58

标签: ruby-on-rails ruby memory-leaks mongoid

在构建关系上的记录时,我遇到了占用过多内存的进程。在谈论这样的代码时应该是这样的:

请注意,ScanItem是Mongoid文档并扫描has_many个项目。

1000.times do
  item = scan.items.build
  item.save
end

我不需要这种关系来保存这些对象,所以我第一次尝试绕过它就是这样的:

1000.times do
  item = Item.new(scan_id: scan.id)
  item.save
end

不幸的是它会产生相同的结果。它不是垃圾收集。这是一个快速测试:

class Foo
end

1000.times do |i|
  foo = Foo.new
  if i % 100 == 0
    ObjectSpace.garbage_collect 
    puts ObjectSpace.each_object(Foo).count 
  end  
end 

# => 1
# => 2
# => 2
# => 2
# => 2
# => 2
# => 2
# => 2
# => 2
# => 2

1000.times do |i|
  item = Item.new(scan_id: scan.id)
  item.save
  if i % 100 == 0
    ObjectSpace.garbage_collect 
    puts ObjectSpace.each_object(Item).count 
  end  
end 

# => 100
# => 200
# => 300
# => 400
# => 500
# => 600
# => 700
# => 800
# => 900
# => 1000

所以我的问题是如何创建带有关系引用的记录而不会因保持这些对象的scan.items关系而导致内存膨胀?它甚至可能吗?

编辑:

即使每隔一段时间用scan方法重新加载reload也无济于事,WeakRef也没有用。

2 个答案:

答案 0 :(得分:2)

问题可能是由身份地图引起的。身份映射将文档存储在内存中,以便可以重复使用它们,而不是为同一文档多次命中db。在rails中,身份映射在每次请求后自动清除,因此通常我们没有注意到内存消耗的差异。但是,在请求 - 响应周期之外工作时,应使用unit_of_work。有关详细信息,请查看Mongoid: IdentityMap

答案 1 :(得分:0)

如果可能,我会尝试利用ActiveRecord find_each

APi on ActiveRecord's Find Each

如果那不可行,那么我会做一个find_in_batches。祝你好运!