Skip to content

Instantly share code, notes, and snippets.

@budu
Created January 6, 2019 23:17
Show Gist options
  • Save budu/7ef8fae1c4d3dc8fbb45a3ff71c9c69c to your computer and use it in GitHub Desktop.
Save budu/7ef8fae1c4d3dc8fbb45a3ff71c9c69c to your computer and use it in GitHub Desktop.
Useful script to help debugging memory leaks
# This script is taken from https://github.com/rails/rails/issues/32892#issuecomment-423376552
require 'ap'
require 'json'
require 'set'
require 'cgi'
require 'byebug'
class Slot
attr_reader :info, :address_to_slot
def initialize info, address_to_slot
@info = info
@address_to_slot = address_to_slot
@can_reach = {}
end
def references
@references ||= (info[__method__.to_s] || []).uniq.map { |a|
address_to_slot[a]
}.compact
end
def address; info[__method__.to_s]; end
def root; info[__method__.to_s]; end
def root?; info["type"] == "ROOT"; end
def reachable? addr, seen = Set.new
return if seen.include?(address)
seen << address
@can_reach.fetch(addr) do
reachable = address == addr || references.any? { |ref|
ref.reachable?(addr, seen)
}
@can_reach[addr] = reachable
end
end
def marked?; @can_reach.values.any?; end
def id; root? ? root : address; end
def label
attributes = %w{ type name file line }.map { |key| info[key] }.compact.map { |k|
CGI.escape_html(k.to_s)
}.join " | "
extras = ''
if @can_reach[address]
extras = "style=bold fontsize=30 fontcolor=red color=red"
end
"#{id.inspect} [label=\"{ #{id} | #{attributes} }\"#{extras}];"
end
def inspect
info
end
def to_s
address
end
end
$address_to_slot = {}
$roots = []
$all_nodes = []
STDERR.puts "Building tree..."
File.open(ARGV.shift, 'r') do |f|
f.each_line do |line|
info = JSON.parse line
slot = Slot.new info, $address_to_slot
$all_nodes << slot
if slot.root?
$roots << slot
else
$address_to_slot[slot.address] = slot
end
end
end
STDERR.puts "Searching needles..."
def reachable?(address)
STDERR.puts " #{address}"
address = address.gsub(/x[0]+/, 'x')
STDERR.puts " #{address} not found in tree" unless $address_to_slot[address]
$roots.map { |root| root.reachable?(address) }.any?
end
ARGV.each do |needle|
reachable? needle
end
STDERR.puts "Generating dot file..."
puts "digraph g {"
puts "node [shape=record];"
empty = true
$all_nodes.each do |node|
next unless node.marked?
puts node.label
node.references.each do |ref|
next unless ref.marked?
empty = false
puts "#{node.id.inspect} -> #{ref.id.inspect}"
end
end
puts "}"
STDERR.puts " dot file empty" if empty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment