Skip to content

Instantly share code, notes, and snippets.

@brianhempel
Last active August 28, 2025 07:07
Show Gist options
  • Save brianhempel/6dae23d52cc7f5071a39 to your computer and use it in GitHub Desktop.
Save brianhempel/6dae23d52cc7f5071a39 to your computer and use it in GitHub Desktop.

Revisions

  1. brianhempel revised this gist Feb 19, 2015. No changes.
  2. brianhempel revised this gist Feb 19, 2015. No changes.
  3. brianhempel created this gist Feb 19, 2015.
    80 changes: 80 additions & 0 deletions bench_rails_memory_usage.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    require "net/http"

    def start_server
    # Remove the X to enable the parameters for tuning.
    # These are the default values as of Ruby 2.2.0.
    @child = spawn(<<-EOC.split.join(" "))
    XRUBY_GC_HEAP_FREE_SLOTS=4096
    XRUBY_GC_HEAP_INIT_SLOTS=10000
    XRUBY_GC_HEAP_GROWTH_FACTOR=1.8
    XRUBY_GC_HEAP_GROWTH_MAX_SLOTS=0
    XRUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=2.0
    XRUBY_GC_MALLOC_LIMIT=16777216
    XRUBY_GC_MALLOC_LIMIT_MAX=33554432
    XRUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=1.4
    XRUBY_GC_OLDMALLOC_LIMIT=16777216
    XRUBY_GC_OLDMALLOC_LIMIT_MAX=134217728
    XRUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=1.2
    rails server -p3009 > /dev/null
    EOC
    sleep 0.1 until alive?
    end

    def alive?
    system("curl http://localhost:3009/ &> /dev/null")
    end

    def stop_server
    Process.kill "HUP", server_pid
    Process.wait @child
    end

    def server_pid
    `cat tmp/pids/server.pid`.to_i
    end

    def memory_size_mb
    (`ps -o rss= -p #{server_pid}`.to_i * 1024).to_f / 2**20
    end

    # In /etc/hosts I have api.rails.local set to 127.0.0.1 for
    # API testing on any app. Curl freaks out and takes extra
    # seconds to do the request to these .local things, so we
    # will use Net::HTTP for moar speed.
    def do_request
    uri = URI("http://api.rails.local:3009/memory_heavy_action")
    req = Net::HTTP::Get.new(uri)
    # Remove the next line if you don't need HTTP basic authentication.
    req.basic_auth("[email protected]", "password")
    req["Content-Type"] = "application/json"

    Net::HTTP.start("localhost", uri.port) do |http|
    http.read_timeout = 60
    http.request(req)
    end
    end

    results = []

    # You can’t just measure once: memory usage has some variance.
    # We will take the mean of 7 runs.
    7.times do
    start_server

    used_mb = nil
    (1..30).map do |n|
    print "Request #{n}..."
    do_request
    used_mb = memory_size_mb
    puts "#{used_mb} MB"
    end

    final_mb = used_mb
    results << final_mb
    puts "Final Memory: #{final_mb} MB"

    stop_server
    end

    mean_final_mb = results.reduce(:+) / results.size
    puts "Mean Final Memory: #{mean_final_mb} MB"