# 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:

```ruby
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:**

1. **Lightweight:** Adds negligible overhead compared to gems like `memory_profiler`
    
2. **Simple:** Just a few lines of core logic
    
3. **Efficient:** File.flush ensures writes survive process crashes
    
4. **Thread-safe:** Runs in background without blocking main process
    

---

## **Key Benefits I Discovered**

1. **Zero Dependencies**  
    No need to add gems to your Gemfile or worry about version conflicts
    
2. **Customizable Logging**  
    Easily adjust:
    
    * Log frequency (from seconds to hours)
        
    * Output format (JSON, CSV, etc.)
        
    * Destination (file, STDOUT, remote service)
        
3. **Low Maintenance**  
    The `/proc` interface has been stable for decades – unlikely to break
    
4. **Surprisingly Portable**  
    Works on:
    
    * Any Linux distribution
        
    * Docker containers
        
    * WSL (Windows Subsystem for Linux)
        

## **Caveats and Alternatives**

1. **Linux-only**  
    For macOS, consider using `ps` command parsing:
    

```bash
rss_kb = `ps -o rss= -p #{Process.pid}`.to_i
```

2. **Not for Detailed Profiling**  
    Use `memory_profiler` if you need object-level granularity
    
3. **Container-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
