Skip to content

Ruby Performance note #17

@hungle00

Description

@hungle00

1. Memory consumption and GC

Print Process RSS

On Linux and Mac OS X you can get RSS from the ps command:

`ps -o rss= -p #{Process.pid}`.to_i
# mb
`ps -o rss= -p #{Process.pid}`.to_i / 1024

Garbage Collector

Compare two same versions of code, one with GC works and one with GC disable

require "benchmark"

num_rows = 100000
num_cols = 10
data = Array.new(num_rows) { Array.new(num_cols) { "x"*1000 } }

GC.disable # just add disable GC in version 2
time = Benchmark.realtime do
  csv = data.map { |row| row.join(",") }.join("\n")
end

puts time.round(2)

Now let’s run this and compare our measurements between 2 versions. On my computer, version 1 takes 2.72s and version 2 takes 1.91s. The percent of time spent in GC is about 30%. We can see our program spends quite a lot of its execution time in the garbage collector.

Of course, we can not disable GC altogether for better performance. Turning off GC significantly increases peak memory consumption. The operating system may run out of memory or start swapping.
We will use RSS to measure object memory before and after GC kick-in

num_rows = 100000
num_cols = 10
data = Array.new(num_rows) { Array.new(num_cols) { "x"*1000 } }

puts "%d MB" % (`ps -o rss= -p #{Process.pid}`.to_i/1024)
GC.disable

data.map { |row| row.join(",") }.join("\n")

puts "%d MB" % (`ps -o rss= -p #{Process.pid}`.to_i/1024)
920 MB
2513 MB

2. Object Memory

Objects

In Ruby everything is an object that’s internally represented as the RVALUE struct. sizeof(RVALUE) is machine dependent:
For example, 40 bytes in 64-bit architecture. Most modern computers are 64-bit, so we’ll assume that one object costs us 40 bytes of memory to create.

A Ruby object can store only a limited amount of data, up to 40 bytes. Slightly less than half of that is required for upkeep. All data that does not fit into the object itself is dynamically allocated outside of the Ruby heap. When the object is swept by GC, the memory is freed.

ObjectSpace library

For example, a Ruby string stores only 23 bytes in the RSTRING object on a 64-bit system. When the string length becomes larger than 23 bytes, Ruby allocates additional memory for it.
We can see how much by calling ObjectSpace#memsize_of, for example, like this:

require 'objspace'

ObjectSpace.memsize_of(Object.new)
# => 40
str = 'x' * 23
ObjectSpace.memsize_of(str)
# => 40
str = 'x' * 24
ObjectSpace.memsize_of(str)
# => 65

https://ivoanjo.me/blog/2021/02/11/looking-into-array-memory-usage/

Metadata

Metadata

Assignees

No one assigned

    Labels

    rubyAbout Ruby and Rails

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions