public
Created

Breadth-first search of memprof heap dump

  • Download Gist
bfs.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
require 'progressbar'
require 'shellwords'
require 'json'
require 'active_support/core_ext/hash/keys'
require 'set'
require 'thread' # queue
 
def main
objs = load_objs
$objs = objs
# These object_ids identify ActiveRecord::Relations from the article
# table which I'm presuming are the ones that are leaked. I had to find
# them in the memprof dump because when I compare
# ObjectSpace.each_object(ActiveRecord::Relation) before and after
# app.get("/"), the object_ids have a different format than those in the
# dump.
oids = Set.new ["0x508d418", "0x5413830"]
path = search_for(objs, oids)
p path
end
 
def load_objs
filename = "myapp_heap.json"
line_count = `wc -l #{filename.shellescape}`.strip.to_i
bar = ProgressBar.new "Reading json", line_count
objs = {}
File.foreach("myapp_heap.json") do |line|
obj = JSON.parse(line)
obj.symbolize_keys!
objs[obj[:_id]] = obj
bar.inc
end
bar.finish
objs
end
 
def search_for(objs, target_oids)
queue = Queue.new
$queue = queue
seen = Set.new
queue.enq ["globals"] # initial
until queue.empty?
path = queue.deq
oid = path.last
$stdout.write "#{oid} depth: #{path.length} / queued: #{queue.length} / seen: #{seen.length} \r"
next if seen.include? oid
seen.add oid
if target_oids.include? oid
return path
end
(ch=child_oids(objs[oid])).each do |child|
child_path = path.dup
child_path.push child
queue.enq child_path
end
end
puts
end
 
def child_oids(obj)
# Perhaps I'm missing some cases here... ?
case obj
when String
if /\A0x[0-9a-f]{1,16}\Z/.match obj
[obj]
else
[]
end
when Array
obj.map {|v| child_oids(v) }.inject([], &:+)
when Hash
obj.map {|k, v| child_oids(v) }.inject([], &:+)
else
[]
end
end
 
if File.identical?(__FILE__, $0)
main
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.