Rubyのアリーナの覗いてみる
最近、変なRubyの重箱の隅をつつくようなプログラムばっかり作っていますが、その1つです。現状のRubyの実現ではObject#__id__で返される値はオブジェクトのアドレスから作るため、Object#__id__の結果をビットシフトすることでRubyレベルでオブジェクトのアドレスが得られます。そして、ObjectSpace#each_objectを使うと全部のオブジェクトが得られます。
これらを利用して、メモリの使用状況を絵にするプログラムを作ってみました。256×256のビットマップをメモリに見立てています。Rubyで使っているところ(正確にはObject#each_objectで手に入れられるオブジェクト)は赤く表示されます。
$no = 0 def make_bmp(memtab) fheader = ['BM', 65536 + 12 + 14, 0, 0, 12 + 14 + 256].pack("a2VvvV") iheader = [12, 256, 256, 1, 8].pack("Vvvvv") black = [255, 255, 255].pack("c3") white = [0, 0, 255].pack("c3") File.open("mem-#{$no}.bmp", "w") do |fp| fp.print fheader fp.print iheader fp.print black fp.print white*255 65535.downto(0) do |i| if memtab[i] then fp.printf "%c", 1 else fp.printf "%c", 0 end end end $no = $no + 1 end def dump_mem max = 0 min = 65536 * 65536 objs = {} ObjectSpace.each_object {|obj| add = ((obj.__id__) >> 1) << 2 if max < add then max = add end if add < min then min = add end } range = max - min if range > 65536 then step = range / 65536 + 1 else step = 1 end printf "Address max %x\n", max printf "Address min %x\n", min printf "step %d\n", step memtab = {} ObjectSpace.each_object {|obj| add = ((obj.__id__) >> 1) << 2 memtab[(add - min) / step] = 1 } make_bmp(memtab) end
サンプルです。
dump_mem # mem-0.bmp str = "" (0..1000).each do |n| str = str + "a" end dump_mem # mem-1.bmp ObjectSpace.garbage_collect dump_mem # mem-2.bmp
dump_memを実行すると、mem-?.bmpというファイルがカレントディレクトリに作られます。?は0から呼ばれた順番に1づつ増えます。
サンプルの実行例です。bmpがアップロードできなかったのでpngに変換しています。
mem-0.bmp
mem-1.bmp
mem-2.bmp