メモリプロファイラ の続き
メモリプロファイルでGCが発生を認識する方法を考えてみました。ファイナライザを使う方法です。
@@gccnt = 0 def MemProf.gchandle lambda {|id| @@gccnt = @@gccnt + 1 GCChecker.new } end class GCChecker def initialize ObjectSpace.define_finalizer(self, MemProf.gchandle) end end GCChecker.new GCChecker.new # ダミー、なぜ必要かわからないし、わかりたくない
こんな感じの考え方です。
- ダミーのオブジェクトを用意してファイナライザを設定しておきます
- オブジェクトは次GCが起きたら回収されるよう一切の参照を切っておきます
- ファイナライザーのハンドラでgcの回数を増やします
- さらに次のダミーオブジェクトを生成してファイナライザーを設定します。
GCChecker.newが2つありますが、なぜか1つだと回収されません。処理系内に秘密の参照があるように感じますが、あまり深入りしたくないのでそっとしておいています。そんな感じですので、バージョンによっては動かないかもしれないという代物です。
GCの回数を数えるバージョンのMemProfですが、不完全です。GCの回数は高々100回以内でオブジェクトの数は何百万になるのでグラフにするとGCの回数が潰れてしまいます。もちろん、グラフや軸を分ければいいのですが、サボってます。
#!/bin/env ruby # # メモリプロファイラ # require 'gnuplot' module MemProf PROFILE_RESOLUTION = 0.01 WATCH_TYPE = [ :TOTAL, :T_ARRAY, :T_STRING, :T_NODE, :T_BIGNUM, :GC ] TEXT_OUTPUT = false GNUPLOT_OUTPUT = true GNPULOT_FORMAT = "png" GNUPLOT_OUTFILE = "foo.png" @@gccnt = 0 def MemProf.gchandle lambda {|id| @@gccnt = @@gccnt + 1 GCChecker.new } end class GCChecker def initialize ObjectSpace.define_finalizer(self, MemProf.gchandle) end end GCChecker.new GCChecker.new # ダミー、なぜ必要かわからないし、わかりたくない mem_snapshot = [] Thread.new(mem_snapshot) do |ms| prevtime = 0 while true do currenttime = Process.times.utime if currenttime - prevtime > PROFILE_RESOLUTION then cntobj = ObjectSpace.count_objects cntobj[:GC] = @@gccnt ms.push [currenttime, cntobj] end prevtime = currenttime Thread.pass end end END { if TEXT_OUTPUT == true then WATCH_TYPE.each do |ev| print "# #{ev} \n" mem_snapshot.each do |t, v| print "#{t} #{v[ev]}\n" end print "\n\n" end end if GNUPLOT_OUTPUT == true then Gnuplot.open do |gp| Gnuplot::Plot.new(gp) do |plot| plot.terminal GNPULOT_FORMAT plot.output GNUPLOT_OUTFILE plot.autoscale plot.title "Memory usage" x = mem_snapshot.map {|n| n[0]} WATCH_TYPE.each do |ev| y = mem_snapshot.map {|n| n[1][ev]} plot.data << Gnuplot::DataSet.new([x, y]) do |ds| ds.with = "line" ds.title = ev end end end end end } end $0 = ARGV[0] fn = ARGV[0] ARGV.shift load fn, true