ActiveRecord不释放内存

问题描述 投票:2回答:1

我有一个导出工作,从我们的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
  1. 它的开头是 76.93359375 MB
  2. 在加载1 Mio对象后,内存增加到 2436.3125 MB
  3. 垃圾回收将内存减少到 2421.046875 MB, 但我希望降幅明显更高!
  4. 有趣的是,第二次运行,只将内存增加到了 2436.3828125 MB
  5. 最后一个 GC.start 莫名其妙 增加 回忆一下 2436.3984375 MB

所以我想知道这怎么可能?ActiveRecord中一定有我不知道的东西,我想知道这一切是如何工作的,为什么内存没有被释放。

按照这个逻辑,内存应该在每个读取数据的请求中增加,但我假设在请求-响应周期内使用时有一些不同的东西。

ruby-on-rails ruby memory memory-leaks rails-activerecord
1个回答
3
投票

加载大型对象,这些对象分布在内存中(而不是像这样的对象)。String 在Ruby中,由于Mark & Sweep算法不能将整个内存块返回给操作系统,所以Ruby中的Hash会有这样的效果。如果你开始解析大的JSON文件(比如10多MB),你会得到类似的效果,因为由此产生的由大量其他对象组成的Hash将和其他仍有活动引用的对象一起被放置在多个内存块中,因此Ruby不能释放该块。

© www.soinside.com 2019 - 2024. All rights reserved.