因此,我的Sidekiq工作人员内存泄漏。我有一台工作服务器,其中只有一个队列用于此工作任务,一周即可达到约10G RSS。
我尝试只用1个工作线程在本地重现它,瞧-我在一夜之间从200M增长到1G,每分钟处理1个任务。自然,我想知道泄漏的内容,所以我也正在记录RSS,heap_live_slots和heap_free_slots。当我绘制结果时,我可以看到RSS稳定增长,而live and free slots随机波动,但界限清晰且恒定,而它们的总和保持不变。
在这一点上,我得出的结论是,泄漏可能不是在Ruby代码中发生的,而是在某些 native 扩展中发生的。所以我通过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大约值(value)200M RSS,但是当我按Ctrl + C并查看jemalloc的统计信息输出时,我会看到完全不同的东西:
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。
因此,我已经更新了所有与 native 扩展相关的gem,这是
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
结果相同:RSS,Memory slots
最佳答案
Ruby 2.4.2 has a known issue with jemalloc
。
该问题已在大约一个月前关闭,但我不知道您使用的软件包是否已打补丁...实际上,我认为该补丁尚未发布。可能所有的jemalloc
统计数据都不相关。
另外,这看起来像X-Y question(您在询问jemalloc
,而您可能希望解决内存“泄漏”问题)。
在假设 native 代码发生内存泄漏(尽管可能性很小)之前,我将考虑任务的作用域如何影响垃圾回收器,并尝试最小化作用域和任何长生命周期变量。
例如,如果您的任务是Proc
,则可能将其绑定(bind)到全局范围,这意味着某些变量可能永远存在...
尝试将任务包含在函数中,并确保在完成任务后没有引用任何变量。
关于ruby - 使用jemalloc调试sidekiq worker内存泄漏,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47220633/