Monitoring Ruby Process Memory Without the Bloat: A Lightweight DIY Approach
The Problem: When Heavyweight Tools Are Too Heavy
Recently, I found myself needing to monitor memory usage in a long-running Ruby process. Like any good developer, I first reached for popular tools like memory_profiler and get_process_mem. But there was a problem: these tools themselves consumed significant memory, which felt ironic when trying to monitor a memory-sensitive process.
I realized I didn't need detailed object allocation traces or complex statistics – I just wanted a simple answer: "How much memory is my process using right now?"
The Discovery: Linux's Proc Filesystem
The solution came from Linux's /proc filesystem, specifically /proc/self/statm. This special file contains memory usage information for the current process in a simple space-separated format.
Key fields:
Field 1: Total program size (virtual memory)
Field 2: Resident Set Size (RSS) - physical memory being used
Field 3: Shared pages
Since we care about actual physical memory usage, RSS (field 2) is our golden number.
The Solution: A Minimal Memory Logger
Here's the core implementation I landed on:
def log_memory_usage(interval: 5, log_path: "memory.log")
Thread.new do
loop do
begin
# Get RSS from proc in pages (1 page = 4KB)
rss_pages = File.read('/proc/self/statm').split[1].to_i
rss_kb = rss_pages * 4
# Append to log file with timestamp
File.open(log_path, 'a') do |f|
f.puts("[#{Time.now.utc.iso8601}] Memory: #{rss_kb} KB")
f.flush
end
rescue => e
$stderr.puts "Memory logging failed: #{e}"
end
sleep(interval)
end
end
end
Why This Works:
Lightweight: Adds negligible overhead compared to gems like
memory_profilerSimple: Just a few lines of core logic
Efficient: File.flush ensures writes survive process crashes
Thread-safe: Runs in background without blocking main process
Key Benefits I Discovered
Zero Dependencies
No need to add gems to your Gemfile or worry about version conflictsCustomizable Logging
Easily adjust:Log frequency (from seconds to hours)
Output format (JSON, CSV, etc.)
Destination (file, STDOUT, remote service)
Low Maintenance
The/procinterface has been stable for decades – unlikely to breakSurprisingly Portable
Works on:Any Linux distribution
Docker containers
WSL (Windows Subsystem for Linux)
Caveats and Alternatives
- Linux-only
For macOS, consider usingpscommand parsing:
rss_kb = `ps -o rss= -p #{Process.pid}`.to_i
Not for Detailed Profiling
Usememory_profilerif you need object-level granularityContainer-Aware
In Docker, remember this shows container memory, not host memory
The Surprising Lesson
Sometimes the simplest solutions are the best. While sophisticated tools have their place, there's value in understanding your platform's fundamentals. By leveraging Linux's built-in instrumentation, I achieved:
Negligible memory footprint compared to gem-based solutions
Custom logging perfectly tailored to my needs
Deeper understanding of process memory management
Try It Yourself!
Next time you need basic memory monitoring, consider this approach. You might be surprised how much you can achieve with:
A few lines of Ruby
Linux fundamentals
A curious mindset




