2011/08/19

Rubyのメモリ利用

GCとcompactionについて色々理解が進んだのでメモ的に書いてみる。

Garbage collectionとは、参照されていないオブジェクトを解放する操作のことである。ここでいう解放とは、必ずしもCで言う所のfree()的な操作とは一致していない。まず、ここをよく理解していなかった。理解してないとどういうことになるかというと、例えばメモリリークについて調べようとしたときに、OSサイドから見える情報で問題が起きているだとかないだとか言ってしまう。

というか、そもそもGCとは逆の確保という操作についてもmalloc()的な操作が絡むとも言えない。これらは、GCがどういう実装になっているかによって、定義が変わってくる。

今回は、Rubyで長時間走るプロセスについてメモリの増加をできるだけ抑えたいという目的があった。ので、ここに書いてあることはRubyはこんな感じにメモリを使うものですよというだけのことである。ややこしいのは、Rubyにはいくつも異なる実装があり、それぞれが異なるGCを持っているということだ。同じ系統の実装でも、バージョンが変われば実装も変わっていることも考えられる。なので、この関係の話をするときはは、どの実装について話をしているのかはっきりさせてすすめるのが良さそうだ。

CRuby 1.8.7 と1.9.2で幾つかテストプログラムを書いて試したところ、こんな流れで動くことがわかった。

a=[]
99999.times { a << {} }

などどすると、Rubyのプロセスが膨れ上がる。
a.clear
とすると、Arrayオブジェクトがimmutableだったとしても、99999個分のHashオブジェクトは解放の対象となるはず。そこで
GC.start
として明示的にGCを走らせる。しかし、psなどから見えるOSプロセスとしてのメモリの利用量の変化はほとんどない。次に同じように、

99999.times { a << {} }

ともう一度やる。今度はOSプロセスとしてメモリの利用量はあまり増えない。

同じように、a.clearしても特に目立った変化はない。ここまでやってみてわかったことは、

  1. CRubyは、必要なメモリがないときはmalloc()的な動作を行いメモリの確保を行う。
  2. オブジェクトへの参照をなくして、明示的にGC.startして解放の処理を行っても、free()的な処理を行ってOSへメモリを返却しているわけではない。
  3. 一度確保されたメモリ領域を超えない範囲で新規オブジェクトの生成を行うと、確保済みの領域を再利用するようだ。
こんな状態なので、CRuby VMの外側からは細かくは何が起きているのかうかがい知ることはできない。

これ以上のことを知るためには、CRuby VMから必要な情報を取得するメモリプロファイラを使うしかない。1.9.2には、GC::Profilerという簡易プロファイラが内蔵されており、それを使っていろんな内容を試すことができる。1.8.7にはmemprof gemがあり、機能的にはこちらのほうが充実しているようだがx86_64環境でしか動かないという事が書いてあった。

もう眠たいので簡単に書くと、GC::Profilerを使うとGC.startする前と後とで大きく変化する値があることが分かる。結果、プロファイラを使うことで分かったことは、「3」で内部的に何が起きていたのかということだけであった。あとは、Rubyのプログラムとしてメモリリークが起こっていそうという時は、これらのツールを積極的に使わないと分からないということもある。

そろそろまとめに入ると、CRubyにとってのGCとは、参照のなくなったオブジェクトを解放することではあるが、確保したメモリの解放を行うという操作ではないということだ。このGCの目的は、メモリをOSに返すことではなく、確保済みのメモリをできるだけ他の新しいオブジェクトで再利用したい、という所にあるようだ。まぁ、こんなことはRubyの本などにはしっかり書いてありそうだけど、ようやく意味が理解できるところまで来たということで。

以上のことから、OSからみたCRubyのメモリ利用の傾向は、
  1. メモリをある程度のサイズずつ必要となるタイミングでmallocしていく。
  2. mallocした範囲はfreeしない。
であることがわかった。デーモンプロセスのような常時起動型のプログラムをRubyで書いているのに、なんて厳しい。

でも、よくよく考えてみると本当に厳しい内容なのかというと実はそうでもないかもしれない。という話を次回やってみたい。


http://www.theirishpenguin.com/2009/10/29/understanding-how-ruby-stores-objects-in-memory-the-ruby-heap/



ATX/EPS 12V 電源

PC自作の話。

自作はもうやらないと決めて早幾年。しかし、にわか自作好きに、訳もわからず買われた機械たちを何とか動かすため色々情報集めをした。

買われたマザーボードは、Supermicroの X7DAL-Eというモデル。対応しているCPUは、Xeonの5300-5400系列。2011年半ばにもなって、なんでこんな数年前の型落ちを買ってくるのか甚だセンスに疑問を感じるが、どうしてもDual CPUをやりたかったのが理由なようだ。今時一つのCPUに何個もCoreが入ってるんだから、Dual CPUにこだわるとか意味が分からない。

そして、電源をつないでいるのに電源が入らないとかいうどうしようもない状態に。一緒に買った電源は、RosewillのRG630-S12と言う奴。まず、マザーボード上の電源コネクタが合わない。RG630が持っているコネクタ(マザーボード用)は、24pin+8pin のみ。X7DAL-Eが必要とするコネクタは、24+8+4というタイプ。PCI-E用の別のコネクタを無理やり差してみたりしていたけれど、何も進展なし。

最近のよくわかってない状態で自作をやるのは嫌くさいという理由で放置していたが、やっぱり動かしたほうがいいということになって悪あがきを始めた。昔自作していた時も、電源のコネクタとか気にしたことがないので、こんなこともあるのかという感じ。

ちょっと調べて理解できたのは以下の範囲。

  • ATX+12V という電源規格がある。
  • それを拡張する形でEPS+12V っていう規格がある。
  • 両方共24pinの電源コネクタがある。これはCPUの電源供給用ではないということが書いてあるページもあった。
  • CPUは、別のコネクタ8pin(EPS)/4pin(ATX) から供給を受ける。
RG630はEPS対応電源でもあるので、4pin+4pinの形で8pinを構成できるようになっていた。しかし、マザーボード上には、24pin, 8pinとは別に、4pinの穴が残っている。

他の製品と比べてみたら、「+12V Rails」と書いてある項目に違いがあることに気がついた。Single, 2, 4 などが書いてあり、2と書いてあるタイプの電源を調べると、たしかに4pinの別のコネクタがついている。おそらくDual CPUのマザーボードにしたために8pinとは別に電源が必要で、それに対応した電源を合わせて買う必要があったということらしい。

RG630 はSingle Railの製品なので、間違った電源を買ってきたということになる。2 Rails 以上の製品を買ってきて動くかどうか試してみようと思う。





2011/08/06

A virgin shot

I have bought an entry level SLR camera so they are the first shot from it. Those pictures come from a dinner with friends at the restaurant provides good meal in this area.

Posted by Picasa

This page is powered by Blogger. Isn't yours?