1. Computing

Exploiting the Garbage Collector

By

Exploiting the Garbage Collector

ObjectSpace is a way to access all of the objects currently alive in a Ruby program. Now this sounds a bit odd, but seeing how Ruby is so dynamic and actually tracks where all the objects are in memory, this is possible and occasionally useful. This would be completely impossible in a language like C++, where memory is meaningless without the context of the code meant to interpret it, but with Ruby, quite possible. This is actually a side-effect of the fact that Ruby is garbage collected.

While most of these methods may seem useful for poking around in Ruby's internals, and are sometimes fun to play with, I can count on one hand the times they've actually been useful. These methods aren't likely to change your entire viewpoint on Ruby, but they are nice to know about, occasionally useful when something goes very wrong, and actually pretty fun to play with in IRB and just poke around. The ObjectSpace module has only a few methods:

  • _id2ref - This converts an object ID (AKA the object's address in memory on most Ruby interpreters) to a normal object reference.
  • count_objects - This returns a hash categorizing the number of objects alive. Each key from the hash is specific to the Ruby interpreter, but the MRI interpreter gives you keys like :TOTAL (the total number of objects alive), :T_CLASS (the number of Class objects), :T_STRING (the number of string objects), etc. This can be useful to track the number of objects alive in a program over time and track down any resource leaks in your program. If your program should be static, not growing or shrinking in memory usage, and is slowly using more memory, you can try to narrow down which types of objects are being created and track down the program with this method.
  • define_finalizer(obj, proc) - This method takes two arguments, an object and a proc. A finalizer is a method that is called just prior to the garbage collector freeing the object, and this adds a finalizer to the object. Just before the obj is deleted, proc will be called.
  • each_object(klass) {|obj| …} - This is perhaps the most used (or abused) method here. This method will iterate over every object in the interpreter, or every object of a type. This can be particularly useful if you must monkeypatch something into specific objects, but don't necessarily know which objects they are. None of these methods are useful in everyday code, so it's difficult to think of a particular use case, but you will probably come across a use at some point. It's also just quite fun to play with in IRB and see all the objects alive in your program. Try it, there are a lot more than you think!
  • garbage_collect - This manually initiates the garbage collector. A garbage collector can be an unpredictable thing. In systems where absolute reliability and predictability are necessary (think avionics and aerospace, not web apps) the unpredictability of a garbage collector often rules out languages like Ruby, C# and Java entirely. However, since you're likely doing something a bit less mission critical (literally, since you're likely not launching satellites with Ruby) a garbage collector is just fine, but it can still pop up and run at just the wrong time. By running this occasionally at times you know the program is not going to be busy, you can make the scheduled runs of the garbage collector much less impactful.
  • undefine_initializer(obj) - This removes an initializer from an object.
  1. About.com
  2. Computing
  3. Ruby
  4. Advanced Ruby
  5. ObjectSpace

©2014 About.com. All rights reserved.