RubyGems: Single/Multi-tons and memorysize 2

Posted by Steve Longdo Wed, 09 Aug 2006 03:41:00 GMT

There is a line in the RubyGems source code, @gempath_searcher ||= Gem::GemPathSearcher.new, from custom_require.rb that seeks to make Gem::GemPathSearcher a Singleton class. For some reason this isn't sufficient as I have seen as many as five instances of it existing in the same thread during profiling of Typo. I am not sure why more than one gets generated. It may relate to Rails aliasing the Kernel.require method after RubyGems has in custom_require.rb.

Review of the source makes me understand why a Gem::GemPathSearcher instance can be so large, it holds the gem specifications for every gem and version on the load path. Running locally this is not a big deal, as you probably don't have a lot of gems and their versions installed. On a shared host though there are tons of gems and versions of gems installed (350+ on my TextDrive server!).

A permanent solution to fix Gem::GemPathSearcher to truly be a Singleton class would probably be something as simple as checking Object.const_defined?(:GemPathSearcher) to see if the class is already in memory.

A quick alternative would be restricting the gem library path to a gem repository other than the shared host's repository. This can be done by exporting the GEM_HOME variable in your shell. There is also a GEM_PATH variable that can be used to support multiple repositories. Examples of how to work with these variables can be found on the Rails wiki. It should be possible to make a repository containing just the gems your app needs and nothing else. This will reduce the memory footprint of Gem::GemPathSearcher quite a bit, no matter how many instances of them there might be!

Obviously I am still learning the implications of RubyGems working together with Rails apps. I apologize for you the reader being dragged along on my quest to learn. Anyone wishing to bring this quest to a quick end just tell me how it ends.

Update: I will continue my research until we arrive at the truth. I still have some other RubyGems optimizing techniques to apply. My hope is using something like the gemconfigure file described in the documentation will be the difference between the Whole Milk Memory and Skim Milk Memory. Also I will reformat the code in the post to be pretty tomorrow. need to add some stuff to scribbish to accomplish this and I want to go to bed now...

RubyGems dependency management and memory use... 8

Posted by Steve Longdo Tue, 08 Aug 2006 06:30:00 GMT

I've been looking into the nebulous matter of Rails memory management lately, using Typo4 as my model app. In my research thus far I have noticed that several of the highest memory using items are from the RubyGems library. Particularly the Gem::GemPathSearcher object. After running a few days I have picked up five instances of it taking up nearly 8MB of RAM which is odd because the first time I profiled it there were only four of them. I am not sure why RubyGems needs to be in memory after the app initially loads, especially the ~1.5MB SourceIndex and the 352 Gem::Specification objects for another ~1.6MB. Seems like wiring of any dependencies could be done once at start up. I am not sure if this relates specifically to how Typo uses RubyGems or if all Rails apps incur the memory overhead penalty for RubyGems. If any one with knoweldge of the internal functioning of RubyGems would take the time to educate me on this it would be much appreciated. Also if someone could explain why RubyGems pops up at all since all Typo dependencies are deployed into the vendor folder.

Another one to watch is the slow accumulation of ActiveRecord::ConnectionAdpaters::MysqlColumn, up to 217 instances in memory. Not a particularly large memory hit, but they have steadily grown in number over the last few days. i may swith over to my Postgres database and see if the same thing happens with its connecton adapter.

Finally the allocation of Array objects is interesting. The number of instances in use has gone down by roughly -2000 instances but the memory use of the remaining Arrays has gone up by about 2MB. I need to explode these Arrays and see what they hold and why they stick around so long. Partial output of profiling included below:

Class x852(21194)
Gem::Version x709(24981)
ActiveRecord::ConnectionAdapters::MysqlColumn x217(35410)
Regexp x1343(52312)
Gem::Dependency x309(53743)
Gem::Version::Requirement x662(59168)
Gem::SourceIndex x1(1563056)
Gem::Specification x352(1714117)
Hash x1257(1858255)
String x117204(3869923)
Gem::GemPathSearcher x5(7901012)
Array x6093(11102839)
TOTAL == 28496875

Please do share your experiences with Rails or RubyGems memory use in the comments.

Typo 4.0 and memory reduction... 4

Posted by Steve Longdo Fri, 04 Aug 2006 22:56:00 GMT

Have you upgraded to the latest Typo release only to find that it hits the per process memory limit on your host? It happened to me.

Here is how I went about reducing the memory footprint of Typo:
  • Removed sidbars that aren't used from the installation.
    • Amazon through XBox.
  • Removed unused requires from environment.rb
    • In particlular aggregation classes for the Sidebars that were removed.
  • Make sure to not load any unnecessary parts of Rails (i.e. ActiveWebService) That's right I use the admin screen to post!
  • Most importantly deleted the sparklines_textfilter.
That last one makes a huge difference in the memory use of Typo. It removes the need to load RMagick saving around ~8MB from your process size. In fact these changes have brought Typo down to about 33MB in memory. Since the average Rails app uses 30MB this isn't too bad, however memory consumption slowly creeps up over a period of days and hits the limit. Seemingly a memory leak. I will be digging into this issue as time allows, but work is keeping me busy.

I will eventually be using a diferent theme but I switched to this one while checking out memory use and haven't spent enough time on my new one yet.

Older posts: 1 2 3 4 5 ... 9