[#42564] [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Makoto Kishimoto <redmine@...>

Feature #4043: =E3=82=B0=E3=83=AD=E3=83=BC=E3=83=90=E3=83=AB=E9=96=A2=E6=95=

15 messages 2010/11/11
[#42774] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/16

まつもと ゆきひろです

[#42834] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — "KISHIMOTO, Makoto" <ksmakoto@...4u.or.jp> 2010/12/21

きしもとです

[#42835] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/21

まつもと ゆきひろです

[#42838] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — "KISHIMOTO, Makoto" <ksmakoto@...4u.or.jp> 2010/12/21

きしもとです

[#42845] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/21

まつもと ゆきひろです

[#42577] Rubyのバグレポートのガイドライン — "Shota Fukumori (sora_h)" <sorah@...>

sora_hです。

11 messages 2010/11/15
[#42588] Re: Rubyのバグレポートのガイドライン — Yugui <yugui@...> 2010/11/18

2010/11/15 Shota Fukumori (sora_h) <sorah@tubusu.net>:

[#42638] Enumerable#categorize — Tanaka Akira <akr@...>

enumerable から hash を生成するメソッドとして

25 messages 2010/11/27
[#42643] Re: Enumerable#categorize — Yukihiro Matsumoto <matz@...> 2010/11/27

まつもと ゆきひろです

[ruby-dev:42520] GC issues

From: SASADA Koichi <ko1@...>
Date: 2010-11-03 08:59:45 UTC
List: ruby-dev #42520
 ささだです。

 GC まわりを見てたんですが、いくつか疑問点がありました。

1. ファイナライザの起動タイミング

 現在、ファイナライザは after_gc_sweep() のタイミングでしか起動されませ
ん。つまり、すべての sweep が完了するまで遅延するわけですが、これは資源
解放のタイミングを遅くすることになるので、まずいような気がします。

 これを、slot_sweep のたびにファイナライザを呼ぶようにしたら、メモリが
少ない環境でも、test-all が最後まで動くようになりました。


2. GC.stress が true 時の挙動

 GC.stress が true の時は、mark/free を行い、オブジェクト空間が(それな
りに)綺麗になっている、ということを期待しているように思いますが、現在は
gc_lazy_sweep() を行うだけなので、まだ sweep が完了していない場合は、
mark などは起こりません。



 とりあえず 1 は問題だろうと思います。

 あと、諸々見ていった結果のパッチ。



Index: gc.c
===================================================================
--- gc.c	(revision 29675)
+++ gc.c	(working copy)
@@ -1043,12 +1043,25 @@ rb_during_gc(void)

 #define RANY(o) ((RVALUE*)(o))

-static VALUE
-rb_newobj_from_heap(rb_objspace_t *objspace)
+VALUE
+rb_newobj(void)
 {
+    rb_objspace_t *objspace = &rb_objspace;
     VALUE obj;

-    if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) {
+    if (during_gc) {
+	dont_gc = 1;
+	during_gc = 0;
+	rb_bug("object allocation during garbage collection phase");
+    }
+
+    if (ruby_gc_stress && !ruby_disable_gc_stress) {
+	if (!garbage_collect(objspace)) {
+	    during_gc = 0;
+	    rb_memerror();
+	}
+    }
+    if (!freelist) {
 	if (!gc_lazy_sweep(objspace)) {
 	    during_gc = 0;
 	    rb_memerror();
@@ -1068,20 +1081,6 @@ rb_newobj_from_heap(rb_objspace_t *objsp
     return obj;
 }

-VALUE
-rb_newobj(void)
-{
-    rb_objspace_t *objspace = &rb_objspace;
-
-    if (during_gc) {
-	dont_gc = 1;
-	during_gc = 0;
-	rb_bug("object allocation during garbage collection phase");
-    }
-
-    return rb_newobj_from_heap(objspace);
-}
-
 NODE*
 rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
 {
@@ -1947,6 +1946,11 @@ slot_sweep(rb_objspace_t *objspace, stru
         objspace->heap.free_num += free_num;
     }
     objspace->heap.final_num += final_num;
+
+    if (final_num > 0) {
+	/* kick finalizer */
+	RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
+    }
 }

 static int
@@ -1976,6 +1980,11 @@ before_gc_sweep(rb_objspace_t *objspace)
     }
     objspace->heap.sweep_slots = heaps;
     objspace->heap.free_num = 0;
+
+    /* sweep unlinked method entries */
+    if (GET_VM()->unlinked_method_entry_list) {
+	rb_sweep_method_entry(GET_VM());
+    }
 }

 static void
@@ -1995,20 +2004,9 @@ after_gc_sweep(rb_objspace_t *objspace)
     }
     malloc_increase = 0;

-    if (deferred_final_list) {
-        /* clear finalization list */
-	RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
-    }
-    else{
 	free_unused_heaps(objspace);
     }

-    /* sweep unlinked method entries */
-    if (th->vm->unlinked_method_entry_list) {
-	rb_sweep_method_entry(th->vm);
-    }
-}
-
 static int
 lazy_sweep(rb_objspace_t *objspace)
 {
@@ -2785,17 +2783,20 @@ run_single_final(VALUE arg)
 }

 static void
-run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE objid, VALUE table)
+run_finalizer(rb_objspace_t *objspace, VALUE objid, VALUE table)
 {
     long i;
     int status;
     VALUE args[3];

-    args[1] = 0;
-    args[2] = (VALUE)rb_safe_level();
-    if (!args[1] && RARRAY_LEN(table) > 0) {
+    if (RARRAY_LEN(table) > 0) {
 	args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
     }
+    else {
+	args[1] = 0;
+    }
+
+    args[2] = (VALUE)rb_safe_level();
     for (i=0; i<RARRAY_LEN(table); i++) {
 	VALUE final = RARRAY_PTR(table)[i];
 	args[0] = RARRAY_PTR(final)[1];
@@ -2828,7 +2829,7 @@ run_final(rb_objspace_t *objspace, VALUE

     key = (st_data_t)obj;
     if (st_delete(finalizer_table, &key, &table)) {
-	run_finalizer(objspace, obj, objid, (VALUE)table);
+	run_finalizer(objspace, objid, (VALUE)table);
     }
 }

@@ -2843,17 +2844,10 @@ finalize_deferred(rb_objspace_t *objspac
     }
 }

-static void
-gc_finalize_deferred(rb_objspace_t *objspace)
-{
-    finalize_deferred(objspace);
-    free_unused_heaps(objspace);
-}
-
 void
 rb_gc_finalize_deferred(void)
 {
-    gc_finalize_deferred(&rb_objspace);
+    finalize_deferred(&rb_objspace);
 }

 static int
@@ -2919,7 +2913,7 @@ rb_objspace_call_finalizer(rb_objspace_t
 	st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
 	while (list) {
 	    struct force_finalize_list *curr = list;
-	    run_finalizer(objspace, curr->obj, rb_obj_id(curr->obj), curr->table);
+	    run_finalizer(objspace, rb_obj_id(curr->obj), curr->table);
 	    st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
 	    list = curr->next;
 	    xfree(curr);
@@ -2973,7 +2967,8 @@ rb_gc(void)
 {
     rb_objspace_t *objspace = &rb_objspace;
     garbage_collect(objspace);
-    gc_finalize_deferred(objspace);
+    finalize_deferred(objspace);
+    free_unused_heaps(objspace);
 }

 /*



 見ながらメモっていったもの。似たような関数があって、ちょっとわからなく
なったので整理。


slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
あるスロットについて、sweep を行う。sweep_slot にあったものを取ってくる。

ready_to_gc(rb_objspace_t *objspace)
GC をやって良ければ(dont_gc || during_gc)TRUE を返す
もし、やっちゃ駄目で freelist が 0 なら、heaps を拡張して対応。

before_gc_sweep(rb_objspace_t *objspace)
mark 終了後、sweep を開始する前処理。

after_gc_sweep(rb_objspace_t *objspace)
sweep 終了後の後処理。

lazy_sweep(rb_objspace_t *objspace)
freelist に何かしらの値が入るまで、lazy sweep を進める。
進めても、freelist に値が入っていなければ、FALSE を返す。

rest_sweep(rb_objspace_t *objspace)
まだ sweep していない slot が残っていれば、それをすべて sweep する。

gc_lazy_sweep(rb_objspace_t *objspace)
Lazy sweep 版 garbage_collect
newobj は、この関数を呼ぶ
- もし、sweep の途中であれば、lazy_sweep() する
  freelist が埋まれば、そこで返す
- mark をする
- 最初の1個のオブジェクトが見つかるまで、sweep をする
  みつかった時点で、sweep 中断

gc_sweep(rb_objspace_t *objspace)
全部 sweep する

------------------------------------------
finalize_list(rb_objspace_t *objspace, RVALUE *p)
p は RVALUE の連結リスト。このリストはファイナライザ対象。

run_final(rb_objspace_t *objspace, VALUE obj)
obj の後始末を行う
- T_DATA の場合は登録された free 関数を呼ぶ
- Ruy レベルでファイナライザが登録されていれば、それを呼ぶ(run_finalizer)

run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE objid, VALUE table)
Ruby レベルで登録されたファイナライザを起動する
- ファイナライザは複数登録されているかも。それが talbe という配列。
- これ、obj 要らないじゃん。
- table って関数名は変な感じ。

run_single_final(VALUE arg)
ファイナライザを一つ起動する。run_finalizerから、rb_protec で呼ばれる。

finalize_deferred(rb_objspace_t *objspace)
遅延されたファイナライザを起動する。
- deferred_final_list で示される連結リスト
- 起動する前に、deferred_final_list をクリア

gc_finalize_deferred(rb_objspace_t *objspace)
ファイナライザを呼んで、その後使われていないヒープを回収。
- finalize_deferred(objspace);
- free_unused_heaps(objspace);
同じようなこと関数が多いので、これは廃止したほうが良さそう。

rb_gc_finalize_deferred(void)
gc_finalize_deferred を、gc.c から呼ぶためのインターフェース。
thread.c で、割り込み処理のところから使われている。
- free_unused_heaps は呼ばなくていいんではないか?
  つまり、after_gc_sweep だけで呼べばいいと思われる。



-- 
// SASADA Koichi at atdot dot net

In This Thread

Prev Next