This article is part of a series. To read more, see What's new in Ruby 2.1?.
Ruby 2.1.0 has been released. Being a point release, there are no major architectural changes and there should be no code breakage. However, included are a number of optimizations as well as a few smaller and very welcome features. The following two features are under the hood, you'll never even know about them in your daily Ruby programming. However, they (hopefully) fix two shortcomings in Ruby.
Previously, all method invocations were resolved every time a method was called. This means looking backward through the inheritance tree to find the method being referenced. While not particularly slow since a good portion of the methods being called are defined on higher level classes or mixin modules and (generally) the higher the method is in the chain, the smaller the method hashes are. However, as soon as you started calling methods from mixin modules, or from superclasses, the slower Ruby got. As object oriented programming is one of Ruby's main selling points, this was a problem.
To try to fix this, a simple global method cache was implemented. It was much easier to implement than a local method cache and sped up the most used methods in any program. However, as program complexity (and number of methods) grows, this global method cache gets slower and slower since it's only able to hold a set number of methods. The global method cache has been replaced by a local method cache for each class.
But the global method cache is gone, method lookups are cached per-class. This should improve the speed of large Ruby programs (especially Rails) that often fill the global method cache quickly. However, there's something new you need to worry about for optimizations: cache invalidations. Every time you make a change to a class' methods the cache is invalidated. While most classes this is not an issue for, classes or objects (adding a new method to an object creates an invisible unnamed class for it) that add many methods dynamically can frequently invalidate the cache, causing more uncached method lookups.
Hopefully this will improve the overall speed of larger Ruby programs (as was said before, this especially applies to Rails) but will not do much of anything for smaller Ruby programs.
The garbage collector is responsible for finding old unused objects and freeing their memory for new objects to be created. Where in more traditional programming languages (C and C++), you must manually free resources when you're finished using them, in Ruby and other garbage collected languages (Java, C# and most any "modern" dynamic language) objects that are no longer referenced are discovered by the garbage collector and freed periodically. This takes a huge burden off the programmer, but at the cost of a garbage collector.
RGenGC is a new garbage collector known as a generational garbage collector, sometimes referred to as an ephemeral garbage collector. This design of garbage collector leverages the fact that most objects collected by the garbage collector were the objects most recently created. In other words, most objects being collected by the garbage collector were temporary objects, used for a short period in a single method and discarded. Generational garbage collectors collect these objects more effectively, putting less strain on the GC when it searches through the older objects to find unreferenced objects.
While the results are not in yet, you should see similar performance upgrades in larger systems as with the improved method cache. Larger systems that make more ephemeral objects will see better performance, while smaller systems should see no difference. However, I have seen some benchmarks that show a small drop in performance, so this may need some fine tuning.