在构建关系上的记录时,我遇到了占用过多内存的进程。在谈论这样的代码时应该是这样的:
请注意,Scan
和Item
是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也没有用。
答案 0 :(得分:2)
问题可能是由身份地图引起的。身份映射将文档存储在内存中,以便可以重复使用它们,而不是为同一文档多次命中db。在rails中,身份映射在每次请求后自动清除,因此通常我们没有注意到内存消耗的差异。但是,在请求 - 响应周期之外工作时,应使用unit_of_work
。有关详细信息,请查看Mongoid: IdentityMap。
答案 1 :(得分:0)
如果可能,我会尝试利用ActiveRecord find_each
APi on ActiveRecord's Find Each
如果那不可行,那么我会做一个find_in_batches。祝你好运!