Write Software, Well

September 22, 2021

Modifying Objects in Place

Every time you create or copy something in memory, you add work for GC. Here are some tips from the book Ruby Performance Optimization to write code without using too much memory.

Modify strings in-place.

Instead of making a changed copy, you change the original string. Look for “bang!” functions, such as trim!, gsub!, slice! etc. Use them when you don’t need the original string.

require_relative "./wrapper" # see above for wrapper script

def modify_strings_in_place
str = "X" * 1024 * 1024 * 10
measure("copy") { tmp = str.downcase }
measure("in-place") { str.downcase! }
end

modify_strings_in_place

# Output
# {"3.0.2":{"gc":"disabled","time":0.01,"gc_count":0,"memory":"10 MB"}}
# {"3.0.2":{"gc":"disabled","time":0.01,"gc_count":0,"memory":"0 MB"}}

Use the shift operator << to append strings, instead of using +=.

When you use +=, Ruby creates an intermediate string and assigns it to the original string after appending.

def append_to_string
measure do
x = "foo"
100_000.times { x += "bar" }
end

measure do
x = "foo"
100_000.times { x << "bar" }
end
end

append_to_string

# Output
# {"3.0.2":{"gc":"disabled","time":9.42,"gc_count":0,"memory":"6412 MB"}}
# {"3.0.2":{"gc":"disabled","time":0.01,"gc_count":0,"memory":"-2 MB"}}

Modify Arrays in-place.

Do not create a modified copy of the same array unless really necessary.

def modify_array_in_place
data = Array.new(100) { "x" * 1024 * 1024 }

measure { data.map { |str| str.upcase } }
measure { data.map { |str| str.upcase! } }
end

modify_array_in_place

# Output
# {"3.0.2":{"gc":"disabled","time":0.12,"gc_count":0,"memory":"100 MB"}}
# {"3.0.2":{"gc":"disabled","time":0.1,"gc_count":0,"memory":"0 MB"}}

Hope that helps.

Subscribe to get future posts via email (or grab the RSS feed)

Comments

No comments yet. Be the first to leave one.

Sign in to leave a comment.