Last active
March 13, 2019 08:00
-
-
Save ydkn/11dc3458377aa93f7cb900dfea5d25d1 to your computer and use it in GitHub Desktop.
Debugging Shoryuken Memory Leak (https://github.com/phstc/shoryuken/issues/401)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'set' | |
require 'json' | |
# find dumps | |
args = Dir.glob('/tmp/heap_*.dump').sort | |
args = [args[0], args[args.length / 2], args[-1]] | |
if args.nil? || args.length < 3 | |
puts "NOT ENOUGH DUMPS" | |
exit 1 | |
end | |
puts args.inspect | |
first_addrs = Set.new | |
third_addrs = Set.new | |
# Get a list of memory addresses from the first dump | |
File.open(args[0], "r").each_line do |line| | |
parsed = JSON.parse(line) | |
first_addrs << parsed["address"] if parsed && parsed["address"] | |
end | |
# Get a list of memory addresses from the last dump | |
File.open(args[2], "r").each_line do |line| | |
parsed = JSON.parse(line) | |
third_addrs << parsed["address"] if parsed && parsed["address"] | |
end | |
diff = [] | |
# Get a list of all items present in both the second and | |
# third dumps but not in the first. | |
File.open(args[1], "r").each_line do |line| | |
parsed = JSON.parse(line) | |
if parsed && parsed["address"] | |
if !first_addrs.include?(parsed["address"]) && third_addrs.include?(parsed["address"]) | |
diff << parsed | |
end | |
end | |
end | |
# Group items | |
diff.group_by do |x| | |
[x["type"], x["file"], x["line"]] | |
end.map do |x,y| | |
# Collect memory size | |
[x, y.count, y.inject(0){|sum,i| sum + (i['bytesize'] || 0) }, y.inject(0){|sum,i| sum + (i['memsize'] || 0) }] | |
end.sort do |a,b| | |
b[1] <=> a[1] | |
end.each do |x,y,bytesize,memsize| | |
# Output information about each potential leak | |
puts "Leaked #{y} #{x[0]} objects of size #{bytesize}/#{memsize} at: #{x[1]}:#{x[2]}" | |
end | |
# Also output total memory usage, because why not? | |
memsize = diff.inject(0){|sum,i| sum + (i['memsize'] || 0) } | |
bytesize = diff.inject(0){|sum,i| sum + (i['bytesize'] || 0) } | |
puts "\n\nTotal Size: #{bytesize}/#{memsize}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ... normal content | |
Thread.new do | |
require 'objspace' | |
ObjectSpace.trace_object_allocations_start | |
sleep 10 | |
while true do | |
filename = "/tmp/heap_#{Time.now.to_i}.dump" | |
GC.start | |
f = ObjectSpace.dump_all(output: File.open(filename, 'w')) | |
f.close | |
puts "DUMPED: #{fname}" | |
sleep 60 | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
concurrency: 32 | |
delay: 30 | |
queues: | |
- [queue1, 6] | |
- [queue2, 9] | |
- [queue3, 1] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment