Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Last active December 10, 2015 01:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenderlove/4357176 to your computer and use it in GitHub Desktop.
Save tenderlove/4357176 to your computer and use it in GitHub Desktop.

(This is a translation of ko1's blog. All mistakes are mine.)

This is the 8th day of the Ruby VM Advent Calendar.

I'm slowly running out of breath.

Today is,

So let's try to take a look at the already introduced ObjectSpace.reachable_objects_from(obj). Currently, if you don't require objspace as require 'objspace', you can't use use the library.

ObjectSpace.reachable_objects_from(obj) lets you follow the direct objects from obj, and returns an enumerable.

Let's look at the following examples:

  1. When obj is ["a", "b", "c"], returns [Array, "a", "b", "c"]
  2. When obj is ["a", "a"], returns [Array, "a", "a"]
  3. When obj is [a = "a", a], returns [Array, "a"]

I don't think 1 is a problem, but do you understand the difference between 2 and 3? When it follows multiple identical objects, it only returns one of them.

Well, if you use this, then you can follow objects from obj. Lets try writing code that finds the memory size for all objects. Be careful! This isn't just "following direct", objects, but "following all objects". That is to say, we'll recursively apply ObjectSpace.reachable_objects_from(obj).

For example, an arrangement like this: [['a' * 100, 'b' * 100], 'c' * 100] will follow three 100 character objects, so it means we want the sum to be 300 bytes (strictly speaking, it will also follow an Array, but this calculation is difficult, so we will exclude it).

For getting the object consumption size, use the ObjectSpace.memsize_of(obj) method. This is in to 1.9.

First off, here is the code:

require 'objspace'
require 'pp'

def memsize_of_all_reachable_objects_from(obj, exclude_class = Module)
  objs = {}
  queue = [obj]
  while obj = queue.pop
    next if objs[obj.object_id]
    next unless reachable_objects = ObjectSpace.reachable_objects_from(obj)
    reachable_objects.each{|o|
      case o
      when ObjectSpace::InternalObjectWrapper
        next if objs[o.internal_object_id]
      else
        next if objs[o.object_id]
      end
      queue.push o if !exclude_class || !o.kind_of?(exclude_class)
    }
    objs[obj.respond_to?(:internal_object_id) ? obj.internal_object_id : obj.object_id] = obj
  end
  objs.inject(0){|r, (_, o)| r += ObjectSpace.memsize_of(o)}
end

memsize_of_all_reachable_objects_from(obj, klass=Module) returns the size of all of the objects reachable from obj. But, the class object specified in the second parameter klass is excluded. The default is the Module class object. That is to say, we can try not following things like Array. If you pass nil, then it will exclude nothing.

Anyway, let's try it out!

p memsize_of_all_reachable_objects_from([['a' * 100, 'b' * 100], 'c' * 100])
#=> 300

It correctly returned 300.

Let's also try including the size of the Array.

p memsize_of_all_reachable_objects_from([['a' * 100, 'b' * 100], 'c' * 100], nil)
#=> 639428

A large number came back. There are a large number of objects reachable from the Array to climb, and it seems the size is also very large (On the way, if you look at objs entry count, you'll understand, but it seems the total number of reachable objects is 5604. However, there is a chance it depends on your environment).

memsize_of_all_reachable_objects_from() is a comparatively easy method, but there is an important warning for when you're using ObjectSpace::InternalObjectWrapper. I'll introduce this the next chance I get (as a connected article). If you're interested, please read ext/objspace/objspace.c.

Anyway, that's it for today.

This was code written RubyConf Taiwan 2012.

Materials: http://www.atdot.net/~ko1/activities/rubyconf.tw2012_ko1.pdf

In the materials, there is a map with explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment