Memory profiling in Ruby
The easiest approach is just calling out to ps with the current pid and receiving the resident set size (amount of physical memory allocated to the process).
def Process.rss; `ps -o rss= -p #{Process.pid}`.chomp.to_i; end
If you're only interested in a temporary heuristic for debugging a particular issue, this is probably fine. It's platform-specific, though, and you don't have any guarantees about what the garbage collector is doing between calls.
You can use , but measuring memory with it requires patching the Ruby interpreter.
There's also the gem, which uses the ObjectSpace allocation tracing API . Since this tracks allocations by origin, it can be resource intensive; in my particular case I found it used more memory than what it was profiling. It's also a young gem and still a bit .
I ended up extracting the core of memory_profiler into a more basic thing which just looks at the total amount of memory allocated over the course of a block, and so is particularly suitable for unit tests:
require 'objspace'
module MemoryUsage
MemoryReport = Struct.new(:total_memsize)
def self.full_gc
GC.start(full_mark: true)
end
def self.report(&block)
rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
full_gc
GC.disable
total_memsize = 0
generation = nil
ObjectSpace.trace_object_allocations do
generation = GC.count
block.call
end
ObjectSpace.each_object do |obj|
next unless generation == ObjectSpace.allocation_generation(obj)
memsize = ObjectSpace.memsize_of(obj) + rvalue_size
# compensate for API bug
memsize = rvalue_size if memsize > 100_000_000_000
total_memsize += memsize
end
GC.enable
full_gc
return MemoryReport.new(total_memsize)
end
end