Get current ruby process memory usage
I'd like to format my Logger
output to include the current memory usage, for part of a long-running process.
Is there anything built-in to Ruby for this, a bit like PHP's memory_get_usage()
? Or do I have to execute some shell commands to get it from ps
?
The NewRelic gem provides simple RSS usage implementations for a number of operating systems and ruby runtimes with their MemorySampler
class.
Include the newrelic_rpm
gem in your Gemfile
and invoke it thus:
NewRelic::Agent::Samplers::MemorySampler.new.sampler.get_sample
and it returns the number of megabytes of memory the current process holds as the RSS.
The implementation prefers in-process counters where available (jruby), use the /proc/#{$$}/status
on Linux, and fall back to ps
everywhere else.
When trying to solve this problem a year ago, I did a lot of online research and API digging and was only able to solve it via a system call to ps.
In both OS X 10.7.2 and Red Hat 4.1.2-13 (on EC2):
pid, size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)
This fetches and places the resident memory size of the process in kilobytes into the size variable.
With a little effort this could be cleaned up, but most of the time is spend calling ps and capturing its output, so I don't think it is worth the time.
Using external commands on Ruby like ps
through using backticks will fork the current process for the duration of running the command. This means that if your Ruby process consumes 300mb, you will need another 300mb just to run any of these `ps -o rss #{$$}`.strip.split.last.to_i
solutions.
On linux based systems you can get process memory information by reading /proc/PID/statm
. The second field is the Resident Set Size in number of kernel pages. Converting the RSS pages to bytes requires you to figure out the kernel page size (most likely 4096).
Here's sample code how to get the rss in kilobytes, works on Linux. I don't know how to do this on OSX or other systems.
module MemInfo
# This uses backticks to figure out the pagesize, but only once
# when loading this module.
# You might want to move this into some kind of initializer
# that is loaded when your app starts and not when autoload
# loads this module.
KERNEL_PAGE_SIZE = `getconf PAGESIZE`.chomp.to_i rescue 4096
STATM_PATH = "/proc/#{Process.pid}/statm"
STATM_FOUND = File.exist?(STATM_PATH)
def self.rss
STATM_FOUND ? (File.read(STATM_PATH).split(' ')[1].to_i * KERNEL_PAGE_SIZE) / 1024 : 0
end
end
# >> MemInfo.rss
# => 251944
You can simple use this puts statement
puts 'RAM USAGE: ' + `pmap #{Process.pid} | tail -1`[10,40].strip
The OS gem has an rss_bytes method.
require "os"
puts "#{OS.rss_bytes / 1_000_000} MB"