Tenderlove Making

Graphing Objects in Memory with Ruby

I was debugging Mechanize the other day, and thought it would be handy to have a graph of objects in memory and they’re relationship with each other. So I put together a simple script that outputs a Graphviz file illustrating what the object points to. Here’s the code:

require 'ograph'
require 'rubygems'
require 'mechanize'

mech = WWW::Mechanize.new
mech.get('http://google.com/')

puts ObjectGraph.graph(mech, /^WWW/)

and the output:

Mechanize Memory Graph for Google

Right now it only supports Arrays, but should be easily extensible to support all other Enumerable types. Here’s the code for ObjectGraph:

class ObjectGraph
  def self.graph(target, class_name = /./)
    stack         = [target]
    object_links  = []
    seen_objects  = []
    seen_hash     = {}

    while stack.length > 0
      object = stack.pop
      next if seen_hash.key? object.object_id
      seen_hash[object.object_id] = 1

      if object.is_a?(Enumerable) && ! object.is_a?(String)
        object.each { |iv|
          if iv.class.to_s =~ class_name || object.is_a?(Enumerable)
            object_links.push([object.object_id, iv.object_id])
            stack.push(iv)
          end
        }
      else
        object.instance_variables.each do |iv_sym|
          iv = object.instance_variable_get iv_sym
          if iv.class.to_s =~ class_name || iv.is_a?(Enumerable)
            object_links.push([object.object_id, iv.object_id])
            stack.push(iv)
          end
        end
      end
      seen_objects.push([object.object_id, object.class])
    end

    s = <<END
digraph g {
    graph [ rankdir = "LR" ];
    node [ fontsize = "8"
           shape = "ellipse"
    ];
    edge [ ];
END
    seen_objects.each { |id, klass|
      s += <<END
      "#{id}" [
      label = "<f0> #{id}|#{klass}"
      shape = "record"
      ]
END
    }
    object_links.each_with_index { |(from, to), i|
      s += "\"#{from}\":f0 -> \"#{to}\":f0 [ id = #{i} ]\n"
    }
    s += "}\n"
    s
  end
end

Update: added Enumerable support, so Hashes are now graphed.

« go back