Skip to content

Fix string memory leaks in Ruby 1.8.6

by Topper on September 4th, 2009

UPDATE: This is rails-incompatible… which sucks.

Ruby 1.8.6 leaks memory in some surprising places. Even gsub and split on the String class cause some bad headaches. If you’re using Haml and 1.8.6 – you are probably in a bit of trouble.
Read more: http://blog.edhickey.com/2008/12/03/memory-leak-in-ruby-186-string-class/

However, simply overwriting the offending methods fixes this memory leak at least. With a weird caveat that you may not use $ variables (eg $1) in any blocks passed to gsub.

Re-read that last sentence… “boom”.gsub(/b(.)/) {|m| $1.upcase} will NO LONGER work. Unfortunately… rails uses that syntax, making this blog post probably moot

[ruby]
class ::String
# This below fixes a bad memory leak in ruby 1.8.6
# http://blog.edhickey.com/2008/12/03/memory-leak-in-ruby-186-string-class/
alias :non_garbage_split :split
alias :non_garbage_gsub :gsub
alias :non_garbage_gsub! :gsub!

def split(char)
holder = char
non_garbage_split(holder)
end

def gsub(*args, &block)
if args.size == 1
non_garbage_gsub(args[0], &block)
else
non_garbage_gsub(args[0], args[1], &block)
end
end

def gsub!(*args, &block)
holder = args[0]
args[0] = holder
non_garbage_gsub!(*args, &block)
end
#end memory leak fixes
end
[/ruby]

  • MarkusQ

    Try something like:

    alias mri_gsub gsub
    def gsub(*args,&block)
    mri_gsub(*args,&block)
    end

    It handles $1 et al fine. Also, you should do the same trick with sub, sub!, etc.

    — MarkusQ

  • MarkusQ

    My bad, I failed to test it thoroughly. It works for special cases, but what is needed is a “works always.”

    — Markus

    P.S. After looking at the C code (and this time testing before I post) I see that File#gets & $_ have the same problem.