From: Masao M. <mu...@hi...> - 2005-11-03 12:24:25
|
むとうです。 先日ちょっとふれましたが、0.14.0はメモリリークの 不具合があります。これについてちょっと整理します。 まずは以下のサンプルを見てください。 ---- require "gtk2" Gtk.init class Test < Gtk::Button; end def test vbox = Gtk::VBox.new 5.times { vbox.add(Test.new("button_test")) } vbox end vbox = test GC.start p vbox.children ---- 0.13.0での結果: [#<Gtk::Button:0xb7c03320 ptr=0x947b528>, #<Gtk::Button:0xb7c0330c ptr=0x947b598>, #<Gtk::Button:0xb7c032f8 ptr=0x947b608>, #<Gtk::Button:0xb7c032e4 ptr=0x947b678>, #<Test:0xb7b69be4 ptr=0x947b6e8>] 本来、Testのインスタンスが返ってくることを期待しているのに、 そのスーパークラスのGtk::Buttonのインスタンスが返ってきてしまいます。 0.13.0までは、GTK+側に渡したオブジェクトを再度取得するとき、 そのオブジェクトがGCされずに生きていたらそれを使い回し、存在しない とき(おそらくはGC後)には新しく生成する、という実装でした。 多くの場合は、Ruby-GNOME2で定義されたクラスをそのまま使うので それを取得する際、それが前のオブジェクト自体なのか、新しいオブジェクト なのかは気にしなくとも問題なく使えます(GTK的には常に同じオブジェクト)。 しかし、上記のようにサブクラスを作った場合には問題になります。 で、0.13.0リリース後にこの問題を指摘されて対応しようとしました。 [1]http://www.yotabanana.com/lab/20050808.html#p02 上記のURLに書いてあるように検討したものの、0.14.0では 全てのメソッド毎にこういった改修をやらずに、なんとか、Ruby/GLibで 対応できないかと考えた結果、オブジェクト生成時にRuby側のグローバル なハッシュテーブルにそのオブジェクトを格納し、GCされることを防ぐ、 ということで解決しようと試みました。 でも、これは私の大勘違いでして、いつまでもGCされないオブジェクトが 残り続けるメモリリークの原因となってしまいました。 数日悩んだのですが、結局、そのオブジェクトの生存期間というのは [1]での考察が妥当(つまり、コンテナクラス(setされる側)の インスタンスの生存期間が自分自身の生存期間、(あるいは明示的に 削除されるタイミング)と思いに至りました。 そこで、Ruby/GLibに以下のマクロを追加しました。 #define G_CHILD_SET(self, id, child) #define G_CHILD_UNSET(self, id) #define G_CHILD_ADD(self, child) #define G_CHILD_REMOVE(self, child) idにはrb_intern()の値を使います。 影響範囲ですが、基本的には全てのset_/get_, add_, remove_系の メソッド、ということになります。 うー、大変だ...。 ただ、これが問題になるのはサブクラス化したWidgetのインスタンスを 再利用するときなので、GtkTextIterやGtkTreeIter等の一部分 に現実的には絞ることができると考えています。 なので、以下のようなステップを踏んで対応していきます。 (1) 0.4.1 まずはRuby/GLibに今回の変更を加えます(加えました)。 Ruby/GLibの(set|get)_propertyとRuby/GTKの一部機能について 今回の変更を加えてリリースします。 ここでのリリースは基本的にはメモリリーク対策版です。 (2) それ以降 まずは0.4.1で問題がきちんと解決できているのか、この変更が間違って いないか(別のメモリリーク等がおきていないか等)を見ます。 その後、少なくとも新規追加メソッドに関してはG_CHILD_*を気にしつつ 実装していきます。 すでにあるメソッドについても追々実装していきます。 須藤さん: できれば須藤さんの担当部分も(2)のタイミングで本対応を実施していただけ ればと思います。 ではでは。 -- .:% Masao Mutoh<mu...@hi...> |