gc_monitorを作ってみた
最近、Railsのメモリリーク絡みで困ることがあったので、何か簡単に(拡張ライブラリを書かずに)GCの状況を把握できないものかと思い、それらしいのを作ってgemにしてみました。
http://github.com/komamitsu/gc_monitor
まぁ、簡単に言うとCGされずに残っているインスタンスの一覧を取得するモジュールです。
使い方は簡単(にしたつもり)。まず
sudo gem source -a http://gems.github.com sudo gem install komamitsu-gc_monitor
で、gemとしてインストール。ところでgithubのgemの名前って、auther-projectなのに今頃気がついた。何だかなぁ…
で、こんな風に使うのです。
require 'rubygems' require 'gc_monitor' require 'date' # 何となく例としてDateを使ってみたので class Date attr_accessor :dummy # GCさせるためダミーのアクセッサを end # Objectを指定すればほぼ全てのインスタンスをモニター # ただし、Stringとかの組み込みクラスや実装上の問題でTimeクラスは対象外 GcMonitor.include_in_subclasses(Date) # 必須ではないけれど、GCされたタイミングで何か処理させたければ(文字列で…) Date.release_hook('puts "i am released."') # リアルタイムで情報取得ができるTCPのインターフェース(これも任意) # $ telnet localhost 4321 # list <= GCされていないインスタンスを列挙 # list 6 <= 生成後、6秒経過したもののみ列挙 # quit <= 切断 GcMonitor.tcp_server('0.0.0.0', 4321) 15.times do o = Date.new o.dummy = 'x' * 100 * 1024 * 1024 # GCしろ、CGしろ sleep 0.5 end # この時点でGCされていないやつを列挙(これも任意、tcp_serverかこれか) # :time => 8 で生成後8秒経過しているもののみ, 引数無しの場合は全て GcMonitor.list(:time => 8).each{|rec| p rec}
とすると、
i am released. i am released. i am released. i am released. i am released. i am released. i am released. i am released. i am released. i am released. i am released. ["Date__fdbd2f89c", {:time=>Mon Aug 10 01:24:13 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd465ec", {:time=>Mon Aug 10 01:24:15 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd465a6", {:time=>Mon Aug 10 01:24:17 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd45d40", {:time=>Mon Aug 10 01:24:18 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd465e2", {:time=>Mon Aug 10 01:24:20 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd46510", {:time=>Mon Aug 10 01:24:22 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd45642", {:time=>Mon Aug 10 01:24:23 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd45eb2", {:time=>Mon Aug 10 01:24:29 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] ["Date__fdbd45dcc", {:time=>Mon Aug 10 01:24:30 +0900 2009, :caller=>["/usr/lib/ruby/1.8/date.rb:754:in `new!'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "hoge.rb:23", "hoge.rb:22:in `times'", "hoge.rb:22"]}] i am released. i am released. i am released. i am released.
で、これを見て「最後に残っているインスタンスは九個だけだねぇ」、「じゃあ六個はGCされたってことかい?」、「まぁそういうこったねぇ」、「なるほどねぇ、どうですもう一杯?」という、まったりした会話につながるのではないでしょうか。
# あと、詳細は上記のgithubのリポジトリにおいてある拙すぎるやっつけREADMEを…
2009-08-10 追記
Railsに使ってみたら色々問題が発覚… 明らかにミスったところもあるのでそれは直そうと思うのだけど、Railsのメタプログラミングとの相性が悪いところもあるので、それはどうしようかなぁ…
いっそ、Cの拡張ライブラリで頑張った方が楽なのかも。