13

バンドラーを使用した Rails 2.3.10 アプリがあります。起動時のメモリ フットプリントは非常に大きくなります (開発モードでは 300MB)。

各 gem が起動時にどれだけのメモリを消費するかを確認したいと思います。

4

3 に答える 3

19

トラフィックやリクエストのない基本的な Rails アプリが、起動時に最大 140MB のフットプリントを持つという問題がありました。

次のアプローチを使用して、バンドラーにパッチを適用することなく、アプリの Gemfile で指定された各 gem のメモリ要件を追跡しました。

  1. rails new myappname新しい空のレールアプリを生成する
  2. Gemfile をメイン プロジェクトからこの新しい Rails プロジェクトにコピーします。
  3. 実行bundle installしてrails serverから、Rails サーバーを起動できること、および必要な基本構成がロードされていることを確認します。
  4. Gemfile を開き、rails gem の仕様を除いて、各行require: falseの末尾に追加します。1 つの名前で指定されているが :require => 'othergemname' を使用して必要な他の gem が古いルビー ハッシュ表記を使用していることを確認して、以下のパターン マッチがそれをキャッチできるようにします。
  5. もう一度実行bundle installして、Gemfile.lock を再生成します。
  6. 次のスクリプトを作成します。このスクリプトは、Gemfile で指定された各 gem を手動で require し、前後に rails プロセスによって消費されるシステム メモリをログに記録します。

    # require_and_profile.rb
    def require_and_profile(gemname = nil)
      unless gemname
        puts "%-20s: %10s | %10s" % ['gem','increment','total']
        return
      end
      # This is how to get memory of calling process in OS X, check host OS for variants
      memory_usage = `ps -o rss= -p #{Process.pid}`.to_i / 1024.0
      require gemname
      puts "%-20s: %10.2f | %10.2f" % [ gemname, (`ps -o rss= -p #{Process.pid}`.to_i / 1024.0 - memory_usage), (`ps -o rss= -p #{Process.pid}`.to_i / 1024.0)]
    end
    
    pattern = /^[^#]*gem[ ]*['"]([^,'"]*)['"][ ,~>0-9\.'"]*(:require[ => ]*['"]([^'"]*)['"][, ])?/
    
    require_and_profile
    File.open('Gemfile').each do |line|
      if line.match(pattern)
      if line.match(pattern)[3]
        require_and_profile line.match(pattern)[3]
      else
          require_and_profile line.match(pattern)[1]
        end
      end
    end
    
  7. 走るrails c

  8. load 'require_and_profile.rb'
  9. 出力には、各 gem がベース アプリのフットプリントに追加する量 (MB 単位) と、gem を含めた後のフットプリントの合計 (合計) が示されます。

これは、たとえば、:asset グループでのみ必要な場合に、ブートでアセット同期を必要としていたことを特定するのに役立ちました。異なるブートアップでは、各 gem のメモリ フットプリントがまったく同じではないことがわかりますが、それを数回実行すると、どれがメモリを消費する gem であるかのパターンが示されます。

于 2013-09-11T02:45:01.783 に答える
0

私は次のようにします:

  • すべての gem が必要なバンドラー内の場所を見つけます。
  • 各 gem が必要になった後、現在のオブジェクト数を取得します ( c = 0; ObjectSpace.each_object { c += 1 })

このようにして、どの gem が最も多くのオブジェクトのインスタンス化を引き起こし、したがって間接的に最も多くのメモリ使用量を引き起こしているかがわかります。

ただし、2 つの注意事項があります。

  • メモリ使用量は実際にはオブジェクトの数に線形ではありませんが、どの宝石が最悪の違反者であるかについて十分な見積もりを得る必要があります
  • すでに指摘したように: gem は必要なときにすべてのコードをロードしない可能性があるため、後でより多くのコードがロードされると、gem によってメモリ使用量が増える可能性があります...
于 2012-10-25T10:47:34.447 に答える