From: nobu.nakada@... Date: 2003-10-01T15:07:57+09:00 Subject: [ruby-dev:21453] Re: deferred finalizers なかだです。 At Fri, 26 Sep 2003 18:46:01 +0900, Nobuyoshi-Nakada wrote: > bisonを使っている、つまり!ruby_parser_stack_on_heap()の場合、パー > ズ中にもオブジェクトが回収されることがありますが、finalizerが定 > 義されていても(次のGCまで)実行されません。 これだけだと、deferred_final_listのオブジェクトが解放されてませ んでした。 また、これとは関係ありませんが、NoMemoryErrorをrescueしても常態 に復帰できなさそうです。 * add_heap()でheapsやheaps_limitsのrealloc()に失敗したときに、 そのまま残っているはずのそれまでの配列も捨ててしまっている * heaps_limitsだけ失敗したときには、二つの長さが一致しない ということで、この二つは一緒に管理したほうがいいんじゃないでしょ うか。 Index: gc.c =================================================================== RCS file: /cvs/ruby/src/ruby/gc.c,v retrieving revision 1.156 diff -u -2 -p -r1.156 gc.c --- gc.c 22 Aug 2003 08:09:57 -0000 1.156 +++ gc.c 1 Oct 2003 04:50:50 -0000 @@ -265,10 +265,12 @@ static RVALUE *deferred_final_list = 0; #define HEAPS_INCREMENT 10 -static RVALUE **heaps; +static struct heaps_slot { + RVALUE *slot; + int limit; +} *heaps; static int heaps_length = 0; static int heaps_used = 0; #define HEAP_MIN_SLOTS 10000 -static int *heaps_limits; static int heap_slots = HEAP_MIN_SLOTS; @@ -284,18 +286,23 @@ add_heap() if (heaps_used == heaps_length) { /* Realloc heaps */ + struct heaps_slot *p; + int length; + heaps_length += HEAPS_INCREMENT; - RUBY_CRITICAL(heaps = (heaps_used>0)? - (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)): - (RVALUE**)malloc(heaps_length*sizeof(RVALUE*))); - if (heaps == 0) rb_memerror(); - RUBY_CRITICAL(heaps_limits = (heaps_used>0)? - (int*)realloc(heaps_limits, heaps_length*sizeof(int)): - (int*)malloc(heaps_length*sizeof(int))); - if (heaps_limits == 0) rb_memerror(); + length = heaps_length*sizeof(struct heaps_slot); + RUBY_CRITICAL( + if (heaps_used > 0) { + p = (struct heaps_slot *)realloc(heaps, length); + if (p) heaps = p; + } + else { + p = heaps = (struct heaps_slot *)malloc(length); + }); + if (p == 0) rb_memerror(); } for (;;) { - RUBY_CRITICAL(p = heaps[heaps_used] = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots)); - heaps_limits[heaps_used] = heap_slots; + RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots)); + heaps[heaps_used].limit = heap_slots; if (p == 0) { if (heap_slots == HEAP_MIN_SLOTS) { @@ -500,5 +507,5 @@ gc_mark_all() init_mark_stack(); for (i = 0; i < heaps_used; i++) { - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if ((p->as.basic.flags & FL_MARK) && @@ -539,6 +546,6 @@ is_pointer_to_heap(ptr) /* check if p looks like a pointer */ for (i=0; i < heaps_used; i++) { - heap_org = heaps[i]; - if (heap_org <= p && p < heap_org + heaps_limits[i] && + heap_org = heaps[i].slot; + if (heap_org <= p && p < heap_org + heaps[i].limit && ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0) return Qtrue; @@ -903,9 +910,44 @@ static void obj_free _((VALUE)); static void +finalize_list(p) + RVALUE *p; +{ + while (p) { + RVALUE *tmp = p->as.free.next; + run_final((VALUE)p); + if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; + } + p = tmp; + } +} + +static void +free_unused_heaps() +{ + int i, j; + + for (i = j = 1; j < heaps_used; i++) { + if (heaps[i].limit == 0) { + free(heaps[i].slot); + heaps_used--; + } + else { + if (i != j) { + heaps[j] = heaps[i]; + } + j++; + } + } +} + +static void gc_sweep() { RVALUE *p, *pend, *final_list; int freed = 0; - int i, j; + int i; unsigned long live = 0; @@ -914,5 +956,5 @@ gc_sweep() if yacc's semantic stack is not allocated on machine stack */ for (i = 0; i < heaps_used; i++) { - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) @@ -934,5 +976,5 @@ gc_sweep() RVALUE *final = final_list; - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (!(p->as.basic.flags & FL_MARK)) { @@ -962,8 +1004,8 @@ gc_sweep() p++; } - if (n == heaps_limits[i] && freed + n > FREE_MIN) { + if (n == heaps[i].limit && freed + n > FREE_MIN) { RVALUE *pp; - heaps_limits[i] = 0; + heaps[i].limit = 0; for (pp = final_list; pp != final; pp = pp->as.free.next) { p->as.free.flags |= FL_SINGLETON; /* freeing page mark */ @@ -985,6 +1027,4 @@ gc_sweep() /* clear finalization list */ if (final_list) { - RVALUE *tmp; - if (rb_prohibit_interrupt || ruby_in_compile) { deferred_final_list = final_list; @@ -992,27 +1032,7 @@ gc_sweep() } - for (p = final_list; p; p = tmp) { - tmp = p->as.free.next; - run_final((VALUE)p); - if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; - } - } - } - for (i = j = 1; j < heaps_used; i++) { - if (heaps_limits[i] == 0) { - free(heaps[i]); - heaps_used--; - } - else { - if (i != j) { - heaps[j] = heaps[i]; - heaps_limits[j] = heaps_limits[i]; - } - j++; - } + finalize_list(final_list); } + free_unused_heaps(); } @@ -1366,5 +1386,5 @@ os_live_obj() RVALUE *p, *pend; - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; for (;p < pend; p++) { if (p->as.basic.flags) { @@ -1399,5 +1419,5 @@ os_obj_of(of) RVALUE *p, *pend; - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; for (;p < pend; p++) { if (p->as.basic.flags) { @@ -1570,4 +1590,16 @@ run_final(obj) void +rb_gc_finalize_deferred() +{ + RVALUE *p = deferred_final_list; + + deferred_final_list = 0; + if (p) { + finalize_list(p); + free_unused_heaps(); + } +} + +void rb_gc_call_finalizer_at_exit() { @@ -1577,14 +1609,7 @@ rb_gc_call_finalizer_at_exit() /* run finalizers */ if (need_call_final) { - if (deferred_final_list) { - p = deferred_final_list; - while (p) { - RVALUE *tmp = p; - p = p->as.free.next; - run_final((VALUE)tmp); - } - } + finalize_list(deferred_final_list); for (i = 0; i < heaps_used; i++) { - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (FL_TEST(p, FL_FINALIZE)) { @@ -1599,5 +1624,5 @@ rb_gc_call_finalizer_at_exit() /* run data object's finalizers */ for (i = 0; i < heaps_used; i++) { - p = heaps[i]; pend = p + heaps_limits[i]; + p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (BUILTIN_TYPE(p) == T_DATA && Index: ruby.c =================================================================== RCS file: /cvs/ruby/src/ruby/ruby.c,v retrieving revision 1.82 diff -u -2 -p -r1.82 ruby.c --- ruby.c 30 Jul 2003 07:08:55 -0000 1.82 +++ ruby.c 15 Aug 2003 02:45:40 -0000 @@ -909,4 +909,7 @@ load_file(fname, script) rb_gc(); } + else { + rb_gc_finalize_deferred(); + } } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦