So I ran into this memory leak about a year ago but had forgotten about it so I’m going to document it in the hopes I check my own blog next time I find it. I came across the leak again when looking into why one of my apps was getting so bloated after running for a few days. The leak has been reported in numerous places but doesn’t appear to have been patched in 1.8.6.
This should demonstrate it:
# Just a helper method to show the memory usage output # @NOTE: Won't work on Windows def log leak='fix' ps = %x(ps u -p #{Process.pid}).strip.split(/\n/).last.split(/\s+/) puts "#{ps[4]} #{ps[5]}" end # This leaks memory def bad "ruby+memory+leak".split('+') end # Defining a variable before the String#split # fixes the leak def good rm = '+' "ruby+memory+leak".split(rm) end puts "VSZ RSS" 500_000.times do |i| good log if i%100000 == 0 end puts "\nWatch me leak!" 500_000.times do |i| bad log if i%100000 == 0 end
So the moral of the story is, make sure to define a variable in methods that use String#split, String#gsub and the like. This doesn’t leak in ruby 1.8.4. I haven’t checked 1.9, but I’ve heard it’s fixed there too.
Here is a more complete script demonstrating the issue with both class and instance methods (since some reporters have mentioned it being strictly a class method problem).



