Daily Code Reading #7 – Rack::MemoryBloat

I’ve decided to skip over the rest of Facets for now in order to read more application code.

This week I’m going through some coderack.org examples, starting with MemoryBloat. coderack.org is a collection of Rack middlewares, which are little snippets of code that can be added to any Rails or Rack web application.

The Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module Rack
  class MemoryBloat
    def initialize(app, logger)
      @app = app
      @logger = logger
    end
 
    def call(env)
      memory_usage_before = memory_usage
      result = @app.call(env)
      memory_usage_after = memory_usage
      @logger.info "MemoryBloat: #{memory_usage_after - memory_usage_before} URL: #{Rack::Request.new(env).url}"
      result
    end
 
    private
    def memory_usage
      `ps -o rss= -p #{$$}`.to_i
    end
  end
end

Example

Processing WelcomeController#index (for 127.0.0.1 at 2010-06-07 15:13:28) [GET]
Parameters: {"action"=>"index", "controller"=>"welcome"}
Completed in 782ms (View: 722, DB: 5) | 200 OK [http://redmine.acheron/]
MemoryBloat: 4828 URL: http://redmine.acheron/

Notice that this request used 4,828K of memory.

Review

MemoryBloat has a simple implementation but it can be very useful to track down memory usage for specific requests.

#initialize

The initialize method takes the Rack application stack (app) and a logger. When used with Rails, the documentation recommends passing Rails.logger in as the logger.

#call

All rack middlewares run call when the application stack is run. MemoryBloat’s call does three things:

  1. It runs the rest of the Rack stack (@app.call(env))
  2. It tracks the memory usage before and after the Rack stack call
  3. It logs the memory usage difference to the @logger

#memory_usage

This method uses ps to find out how much RSS memory the current process is using. It’s a crude but effective method, assuming you don’t run on Windows.