使用jemalloc

时间:2017-11-10 10:27:00

标签: ruby memory-leaks sidekiq jemalloc

所以,我的Sidekiq工作人员有内存泄漏。我有一个工作服务器,只有一个队列用于此工作任务,一周内可以获得大约10G的RSS。

我尝试在本地只用1个工作线程重现它 - 瞧 - 我在一个晚上从200M到1G,处理1个任务/分钟。当然,我想知道泄漏了什么,所以我也记录了RSS,heap_live_slots和heap_free_slots。当我绘制结果时,我可以看到稳定的RSS增长,而live and free slots随机波动,但是在明确定义的和恒定的边界内,而它们的总和保持不变。

此时我得出的结论是泄漏可能不是出现在Ruby代码中,而是出现在某些原生扩展中。所以我通过RVM重新安装了带有Jemalloc支持的ruby: rvm reinstall 2.4.2 --with-jemalloc

然后我设置MALLOC_CONF

export MALLOC_CONF='prof_leak:true,lg_prof_sample:0,prof_final:true,stats_print:true'

点燃Sidekiq。刚开始使用1个工作线程的Sidekiq值得大约200M RSS,但是当我按下Ctrl + C并查看jemalloc的stats输出时,我看到完全不同的东西:

Arenas: 32
Quantum size: 16
Page size: 4096
Maximum thread-cached size class: 32768
Allocated: 34056, active: 61440, metadata: 2949272, resident: 2981888, mapped: 6352896, retained: 2035712

什么? 6M映射?这不可能是真的。所以我开始irb并执行以下操作:

2.4.2 :001 > arr = []
 => [] 
2.4.2 :002 > loop do
2.4.2 :003 >   arr << 'a'*10000000
2.4.2 :004?>   sleep 1
2.4.2 :005?> end

在等到irb进程爬升到大约1G RSS之后我停止了这个过程...并看到完全相同的数字。也许可视化调用图将帮助我理解正在发生的事情?

jeprof --show_bytes --pdf `which ruby` jeprof.10536.0.f.heap > ruby.pdf

Using local file /home/mhi/.rvm/rubies/ruby-2.4.2/bin/ruby.
Using local file jeprof.10536.0.f.heap.
No nodes to print

所以有些事情显然是错误的,这就是我需要帮助搞清楚的事情。

以下是jemalloc stat的全部输出:https://pastebin.com/RiMLtqA6

UPD。

所以我更新了所有与原生扩展相关的宝石,这里的输出 bundle exec ruby -e 'puts Gem.loaded_specs.values.select{ |i| !i.extensions.empty? }.map{ |i| "#{i.name} #{i.version}" }'

io-console 0.4.6
nokogiri 1.8.1
bcrypt 3.1.11
debug_inspector 0.0.3
binding_of_caller 0.7.2
json 2.1.0
capybara-webkit 1.14.0
damerau-levenshtein 1.3.0
unf_ext 0.0.7.4
eventmachine 1.2.5
ffi 1.9.18
kgio 2.11.0
msgpack 1.1.0
mysql2 0.4.9
rainbow 2.2.2
raindrops 0.18.0
rbtrace 0.4.8
stackprof 0.2.10
therubyracer 0.12.3
unicode 0.4.4.4
unicorn 5.3.0

结果相同:RSSMemory slots

1 个答案:

答案 0 :(得分:2)

Ruby 2.4.2 has a known issue with jemalloc

该问题大约在一个月前关闭,但我不知道您使用的软件包是否已修补...实际上,我认为该修补程序尚未发布。可能所有jemalloc统计数据都无关紧要。

此外,这似乎是X-Y question(您正在询问jemalloc,而您可能想要解决内存问题&#34;泄漏&#34;)。

在假设本机代码中存在内存泄漏之前(虽然有明显的可能性),我会考虑任务的范围可能如何影响垃圾收集器并尝试最小化范围和任何长寿命变量。

例如,如果您的任务是Proc,它可能绑定到全局范围,这意味着某些变量可能永远存在...

尝试将任务包含在函数中,并确保在任务完成后不会引用任何变量。