我有一个导出工作,从我们的MySQL DB中导出大量的数据。随着数据的增加,我注意到这个侧基q作业占用了太多的内存。服务器有32GB,在导出完成后,需要28GB。当我停止sidekiq进程时,内存使用量下降到8GB。
我已经按照这里的指导进行了操作 https:/github.commperhamsidekiqwikiProblem-and-Troubleshooting。
MALLOC_ARENA_MAX=2
ActiveRecord::Base.connection.clear_query_cache
我在 Ruby 2.6.5p114 并试图通过在生产中创建一个新的rails应用来隔离问题,并使用我的DB作为后端。
gem install rails --version 5.2.4.3
rails new debug -d mysql
我创建了一个空的模型,以避免在我的代码中使用可能导致问题的自定义方法。
class Variant < ApplicationRecord
end
这个脚本只是简单地从数据库中加载了1个Mio对象 并打印出内存使用情况。
# memory.rb
def memory
(`ps -o rss= -p #{Process.pid}`.to_i.to_f / 1024).to_s + " MB"
end
def load_variants
puts "load_variants..."
Variant.uncached do
variants = Variant.limit(1_000_000).to_a
puts "variant.count: #{variants.count}"
end
end
puts memory
load_variants
puts memory
puts "GC.start..."
GC.start
puts memory
# second run
load_variants
puts memory
puts "GC.start..."
GC.start
puts memory
这是输出结果:
root@6e79d7a97d9c:/usr/src/debug# rails r memory.rb
76.93359375 MB
load_variants...
variant.count: 1000000
2436.3125 MB
GC.start...
2421.046875 MB
load_variants...
variant.count: 1000000
2436.3828125 MB
GC.start...
2436.3984375 MB
76.93359375 MB
2436.3125 MB
2421.046875 MB
, 但我希望降幅明显更高!2436.3828125 MB
GC.start
莫名其妙 增加 回忆一下 2436.3984375 MB
所以我想知道这怎么可能?ActiveRecord中一定有我不知道的东西,我想知道这一切是如何工作的,为什么内存没有被释放。
按照这个逻辑,内存应该在每个读取数据的请求中增加,但我假设在请求-响应周期内使用时有一些不同的东西。
加载大型对象,这些对象分布在内存中(而不是像这样的对象)。String
在Ruby中,由于Mark & Sweep算法不能将整个内存块返回给操作系统,所以Ruby中的Hash会有这样的效果。如果你开始解析大的JSON文件(比如10多MB),你会得到类似的效果,因为由此产生的由大量其他对象组成的Hash将和其他仍有活动引用的对象一起被放置在多个内存块中,因此Ruby不能释放该块。