RubyKaigi2018 基調講演2日目レポートで書かなかったことの補足
本記事は上記リンクの記事に関する補足です。プログラミング初心者です、Rails しかやってません、みたいな人でもわかることが望ましいとは思っていたのですが紙面の都合及びやたら技術解説がある記事になってもなあと思い書きませんでした。
明らかに説明足りてねーよな、というところについて補足します。
バインディング
Ruby/GTK3はGTK+プロジェクトのRubyバインディングです。言い換えると,C言語で書かれたGTK+にあるAPIをRubyから実行できるようにするライブラリです。
「バインディング」というのがそもそも「他言語で書かれたライブラリにあるAPIを、ある言語で実行できるようにするもの」みたいな感じですかね。別の言葉では ffi ( foreign function interface )
と呼ばれています。wikipedia によると ffi は Common Lisp 由来の言葉で、バインディングというのが Ada などに由来すると書かれています。
C や C++ で書かれているミドルウェアより下のレイヤについて Ruby などのからアクセスするのはだいたいバインディングの形式をとっている気がします。たまーにそういったバインディングではなくピュア実装です、と銘打ってるライブラリがあったりします。例えば nodejs の mysql ライブラリは "A pure node.js JavaScript Client implementing the MySql protocol." と自称しています。おそらくですがバインディングを使うとC, C++ のレイヤでブロックしてしまいノンブロッキングにならないからだと思います。
rb_gc_adjust_memory_usage
バインディングを利用していると、あるオブジェクトを new するときに実際には他にメモリ領域を確保している、ということが起きがちです。
- Ruby レベルで
foo = MyLib::Foo.new
する - バインディングしてるCレベルで malloc がおきる <- コレ
- foo がスコープを抜けたとかでGCされる
- foo のデストラクタで free される
Ruby は GC があるので上記のままでも特に問題がないように思えますが、このままではGCを実行すべきタイミングをうまく予想できないという問題が隠れています。
Ruby から見るとあくまでも foo
は MyLib::Foo
インスタンス1つ分のメモリしか使用していません。そのため Ruby は「まだ全然メモリ使ってないからGCしなくていいや」という判断をしてしまいます。しかし実際には malloc
で確保されたメモリも使っています。これが記事中の「Ruby本体以外から確保されたメモリ量を認識できない」という問題です。
追加された rb_gc_adjust_memory_usage
関数は、malloc, free したメモリ量を記録することで Ruby に使用しているメモリ量を認識させることができます。