Rubyは本当にメモリを大量に消費しますが、その価値は十分にあります。
メモリ使用量を低く抑えるために何をしていますか? 大きな文字列を避けて、代わりに小さな配列/ハッシュを使用しますか?それとも、ガベージ コレクターに任せても問題ありませんか?
編集: このトピックに関する素敵な記事をここで見つけました- 古いですが、それでも興味深いです。
Phusion の Ruby Enterprise Edition (大幅に改善されたガベージ コレクションを備えたメインライン Ruby のフォーク) がメモリ使用量に劇的な違いをもたらすことを発見しました...さらに、それらはインストールを非常に簡単にしました (必要に応じて削除することもできます)。必要性を見つけます)。
詳細については、Web サイトでダウンロードしてください。
それほど重要ではないと思います。メモリ消費を改善するためにコードを読みにくくすることは、必要な場合にのみ行うべきです。また、必要に応じて、パフォーマンス プロファイル の特定のケースと、変更が問題に対処することを示す特定の指標を用意することを意味します。
メモリが制限要因になるアプリケーションがある場合、Ruby は最良の選択ではない可能性があります。とは言っても、Rails アプリは通常、Mongrel インスタンスごとに約 40 ~ 60 MB の RAM を消費することがわかりました。物事のスキームでは、これはあまりありません。
JRuby を使用して JVM 上でアプリケーションを実行できる可能性があります。現在、Ruby VM はメモリ管理とガベージ コレクションに関して JVM ほど高度ではありません。1.9 リリースでは多くの改善が加えられており、開発中の代替 VM もあります。
私は Ruby 開発者ではありませんが、いくつかの手法と方法はどの言語にも当てはまると思います。
ジョブに適した最小サイズの変数を使用する 使用して
いないときは変数と接続を破棄して閉じる
ただし、オブジェクトがある場合は、何度も使用する必要がある場合は、スコープ内に保持することを検討してください 大きな文字列の操作を伴うループ dp での作業より小さな文字列を作成してから、より大きな文字列に追加します
オブジェクトと接続が閉じていることを確認するために、適切な (catch finally を試行する) エラー処理を使用します。
データセットを扱う場合、必要最小限のものだけを返します
スモールメモリソフトウェア-メモリが制限されたシステムのパターンを見てください。どのような種類のメモリ制約を指定するかは指定しませんが、RAMを想定しています。Ruby固有ではありませんが、この本にはいくつかの有用なアイデアが含まれていると思います。パターンはRAM、ROM、およびセカンダリストレージをカバーし、小さなデータ構造、メモリ割り当て、圧縮、セカンダリストレージ、およびスモールの主要な手法に分けられます。建築。
次のようなコードは避けてください。
str = ''
veryLargeArray.each do |foo|
str += foo
# but str << foo is fine (read update below)
end
これにより、各中間文字列値が String オブジェクトとして作成され、次の反復でその唯一の参照が削除されます。これにより、ガベージ コレクションが必要な文字列がますます長くなり、メモリが大量に消費されます。
代わりに、次を使用しますArray#join
。
str = veryLargeArray.join('')
これは C で非常に効率的に実装されており、文字列作成のオーバーヘッドは発生しません。
更新: ジョナスは、以下のコメントで正しいです。私の警告は には当てはまりますが、 には当てはまり+=
ません<<
。
実際に心配する価値のある唯一のものは、RMagick です。
解決策は、RMagick バージョン 2 を使用していることを確認Image#destroy!
し、イメージの使用が完了したら呼び出すことです。
極端な場合を除いて、メモリ使用量は心配する必要はありません。メモリ使用量を削減するために費やす時間は、大量のギガバイトを購入します。
心に留めておくべきことは、オブジェクトのライフサイクルです。オブジェクトがあまり渡されない場合、ガベージコレクターが最終的に作動してそれらを解放します。ただし、それらを参照し続けると、ガベージ コレクターがそれらを解放するために数サイクルが必要になる場合があります。これは特に、Ruby 1.8 に当てはまります。ガベージ コレクターが使用するマーク アンド スイープ手法の実装が不十分です。
オブジェクトを長時間メモリに保持するデコレータなどの「設計パターン」を適用しようとすると、このような状況に陥る可能性があります。例を単独で試してみると明らかではないかもしれませんが、何千ものオブジェクトが同時に作成される現実世界のアプリケーションでは、メモリの増加によるコストが大幅に増加します。
malloc(3) の実装をjemallocに置き換えると、メモリ消費量が最大 30% 減少します。これを即座に実現するために、「jemalloc」gem を作成しました。
私は Ruby についてはまったくの初心者ですが、これまでのところ、この点に関して特別なことをする必要があるとは思いませんでした (つまり、私が一般的にプログラマーとして行う傾向があることを超えて)。おそらくこれは、メモリを真剣に最適化するのにかかる時間よりもメモリが安いためです (私の Ruby コードは 4 ~ 12 GB の RAM を搭載したマシンで実行されます)。また、私が使用しているジョブが長時間実行されていないためかもしれません (つまり、アプリケーションに依存することになります)。
私は Python を使用していますが、戦略は似ていると思います。
小さな関数/メソッドを使用して、呼び出し元に戻ったときにローカル変数が自動的にガベージ コレクションされるようにしています。
大きな関数/メソッドでは、不要になった大きな一時オブジェクト (リストなど) を明示的に削除します。リソースをできるだけ早く閉じることも役立つ場合があります。
可能であれば、他のデータ構造ではなく配列を使用してください。整数が使用できる場合は、浮動小数点数を使用しないようにしてください。
gem/library メソッドを使用するときは注意してください。メモリが最適化されていない可能性があります。たとえば、Ruby PG::Result クラスには、最適化されていないメソッド「values」があります。大量の余分なメモリを使用します。私はまだこれを報告していません。
配列、リスト、データセットをできるだけ小さくするようにしています。最近のほとんどの言語では、作成とガベージコレクションが非常に高速であるため、個々のオブジェクトはそれほど重要ではありません。
データベースからある種の巨大なデータセットを読み取る必要がある場合は、最初にすべてをメモリにロードするのではなく、順方向/のみの方法で読み取り、少しずつ処理するようにしてください。
多くのシンボルを使用しないでください。シンボルはプロセスが強制終了されるまでメモリに残ります。これは、シンボルがガベージ コレクションを取得しないためです。