使用jemalloc调试sidekiq worker内存泄漏

Rom*_*man 12 ruby memory-leaks sidekiq jemalloc

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

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

在这一点上,我得出结论,泄漏可能不是在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
Run Code Online (Sandbox Code Playgroud)

什么?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
Run Code Online (Sandbox Code Playgroud)

在等到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
Run Code Online (Sandbox Code Playgroud)

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

以下是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
Run Code Online (Sandbox Code Playgroud)

相同的结果:RSS,内存插槽

Mys*_*yst 2

Ruby 2.4.2 有一个已知的jemalloc.

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

另外,这似乎是一个XY 问题(您正在询问jemalloc,而您可能想要解决内存“泄漏”的问题)。

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

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

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