I love to code in Ruby… I’ve stated that many times. It’s a simple, intuitive, unobstrutive language good for quick prototyping and has a lot of good libraries around. There’s one annoiance, though, that every now and then pops up and makes my life miserable. For the last 10 days I’ve been fighting (and loosing) a battle against a memory leak… And this is its story:
I’ve told you that my company has some internal projects using XMPP. I’ve even published a fork of XMPP4R-Simple and presented it in FISL10. XMPP4R, which is the library underneath it, has causing me problems (at least I think it is guilty). This project has a lot of parsing and message/events exchange between XMPP agents. Everything is fine with the test suite and development tests went ok… but when I got it into production, it lasted a day before even the most simple test end up eating all the memory in the server.
Of course… my first thought was that our parser was the guilty one. It’s common knowledge that implementing parsers is not so intuitive in Ruby and one has to pay attention to some glitches not to end up in a memory leak (Why has commented about it before). I’ve rewrote the entire parser and the same behaviour emerged… I’ve even began considering using Treetop and stop worrying about parse construction (I hope treetop would do it The Right Way(tm)), but then I decided it’s worth a little research on the issue.
First, I tried to recompile Ruby 1.8.7 (I was using the one packaged for Debian). Same behaviour. Then I’ve tried Ruby 1.9.1 (I already had it compiled, but I recompiled it anyway 😉 ). Same behaviour. I would not like to try JRuby: even if it fixes the memory leak, it will not be available in all production environments we expect…
This brought me to the important conclusion that there’s no really good tools for memory profiling Ruby programs. There’s a lot of attempts and some even get you an idea of what’s going on, but nothing that points to the really obvious “perpretator” of a memory leak… Also, many people have dealt with this before and it seems to be a pain for everyone.The problem just grows with the complexity of your program and the number of dependencies. To break it up for my case, I designed a Test Case that would require only basic stuff and do the minimal thing (it’s really nothing big and a bit hackish, but it spits a lot of info on what is going on)…
I ended up convinced that either XMPP4R or REXML (which comes with Ruby) are leaking memory (maybe both). Even if it is REXML the faulty library, I suspect XMPP4R guys would like to know about it and would help me to narrow it down. At their home page they even list some desired information on bug reports:
- Contact information
- XMPP4R version or Git SHA1 commit
- Use Jabber::debug = true but remove any sensitive information
- Describe your environment (Ruby version, OS, server software)
- Cool hackers send test cases
All obvious stuff, and since I’ve already built a test case