この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
ある日、mongrelプロセスのメモリ使用量を何となく見ていたところ、
同じ処理をしている他のサーバのものと明らかに違う数値を出していた。
これってもしかして、メモリリークってやつ?
言葉はよく聞くけど、自分自身があまりこれに悩まされた事がなかったため、
今回、ちゃんと正面から向き合う事にした。このメモリリークってやつに。
1. メモリリークとは?
今更だけど、要は使用可能なメモリ容量がどんどん減っていくこと。
アプリケーションが処理のために使ったメモリは、使い終わったら解放される
のが普通だけど、これが何らかの理由で解放されずに残ってしまう事を言う。
借りたものを返さない・・・・どこの世界にも不適な輩はいるらしい。
勘違いしがちなのは、メモリをいっぱい使うのとは直接関係ないという事。
一時的にメモリを大量消費する処理があったとしても、終わった後に解放
されるなら、それはメモリリークじゃない。
むしろ、メモリリークはもっと地味なものらしく、同じ処理が何千回も実行
されて初めて「なんか怪しくね?」って話になる事もざらだとか。
2. GC = Garbage Collecter
さて、メモリリークについて調べてたら、こんな単語に行き着いた。
GC。処理が終わった後、使われなくなったメモリを自動的に回収し、
メモリリークを起きにくくする機能。そういえば、昔読んだRubyの
入門書にも、そんな事書いてあった気がするなあ。
そんなのがあるんだったら、Rubyに関してはメモリリークを気にする
必要はないじゃん、と思ったんだけど、本当にそうなのか?
試しに「ruby」「メモリリーク」で検索かけてみる。
なんだよ、結構出てくるじゃん。
いろいろ調べてわかった事は、このGC。決して完璧なわけじゃない。
例えばメモリ上に、まだ使ってるのか使ってないのかわからないオブジェクト
があった場合、強気に解放してしまうGCと、弱気に様子を見るGCの二種類が
あって、Rubyの場合は後者を使用しているとの事。
だから、本当は参照されてないのに、いつまでも解放されず、結果的に
メモリリークになってしまう事があるのだと。
あと話は変わるけど、RubyのライブラリにはC言語で書かれているものが
あって、扱うオブジェクトの中にRubyのオブジェクトじゃないものがある
ために、それらがGCの対象にならず、メモリーリークの要因になる可能性
もあるんだとか。
ただ、こういうのはすぐに報告されて、バージョンアップで修正されてる
みたいだから、バージョンに気を付けて使っていれば問題ないんじゃないか
と思う。
3. で、結局、冒頭の話はメモリリークだったのか?
わからん。
とりあえずmongrelを再起動したら(当たり前だけど)元に戻ったので、
しばらく様子見かなあ。
メモリリークの原因を追及するのと、定期的にmongrelを再起動するの
だったら、後者の方が楽だしなあ。
まあ、あとは常駐プロセスじゃないpassengerとか、近頃噂のunicornとやらを
試してみるのも手か。
最後に。Rubyのメモリリーク検出ツールなるものを見つけました。
英語マニュアルしかなかったので、自分はわかった風なところまでしか
行きませんでしたが、良かったらチャレンジしてみてください。
<Ruby用メモリリーク検出ツール「Bleak_house」>【動作環境】
UNIX系OS
Ruby1.8.7
【インストール】
$ gem install bleak_house
【セットアップ】
config/environment.rbに以下の1行を追加。
require ‘bleak_house’ if ENV[‘BLEAK_HOUSE’]
【使い方】
1. アプリケーションサーバを起動
$ RAILS_ENV=production BLEAK_HOUSE=1 ruby-bleak-house ./script/server
2. 200〜300リクエストを投げたところで、サーバを停止(Ctrl-C)。
3. /tmp以下にダンプファイルが出来ているので、その内容を解析。
$ bleak /tmp/bleak.20349.000.dump
【参考URL】
http://blog.evanweaver.com/files/doc/fauna/bleak_house/files/README.html