Created
January 6, 2019 23:17
-
-
Save budu/7ef8fae1c4d3dc8fbb45a3ff71c9c69c to your computer and use it in GitHub Desktop.
Useful script to help debugging memory leaks
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
# 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