From: imasahiro9@... Date: 2014-10-27T02:50:42+00:00 Subject: [ruby-dev:48706] [ruby-trunk - Bug #10431] [Open] Can't sweep garbage object immediatly when GC_ENABLE_LAZY_SWEEP=0 Issue #10431 has been reported by Masahiro Ide. ---------------------------------------- Bug #10431: Can't sweep garbage object immediatly when GC_ENABLE_LAZY_SWEEP=0 https://bugs.ruby-lang.org/issues/10431 * Author: Masahiro Ide * Status: Open * Priority: Normal * Assignee: * Category: core * Target version: current: 2.2.0 * ruby -v: ruby 2.2.0dev (2014-10-26 trunk 48073) [x86_64-darwin14] * Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN ---------------------------------------- GC_ENABLE_LAZY_SWEEP=0と設定してrubyをビルドし,以下のコードを 実行した場合,GC時にオブジェクトが解放されていないように見えます. ~~~ $ ../configure CFLAGS="-DGC_ENABLE_LAZY_SWEEP=0" && make miniruby $ cat bug2.rb GC.disable 10000.times { Object.new } total_freed_objects1 = GC.stat[:total_freed_objects] GC.enable GC.start(full_mark: true, immediate_sweep: true) total_freed_objects2 = GC.stat[:total_freed_objects] puts "freed object : #{total_freed_objects2 - total_freed_objects1}" $ ./miniruby -v ruby 2.2.0dev (2014-10-26 trunk 48073) [x86_64-darwin14] $ ./miniruby bug2.rb freed object : 0 ~~~ また,rubyのコンパイルフラグをGC_ENABLE_LAZY_SWEEP=0, RGENGC_CHECK_MODE=1と設定した上でビルドし,以下のコードを実行すると assertで落ちます. ~~~ $ ./miniruby -e '10000.times { Object.new }' Assertion failed: (objspace->flags.stat == gc_stat_none), function gc_start, file ../gc.c, line 5802. [1] 91336 abort ./miniruby -e '10000.times { Object.new }' ~~~ sweepフェーズにてGC_ENABLE_LAZY_SWEEP!=1の時のみsweepが実行されるのが 原因のようですので,これを修正するパッチを作りました. ~~~ diff --git a/gc.c b/gc.c index a27cc01..979e2e0 100644 --- a/gc.c +++ b/gc.c @@ -3314,9 +3314,8 @@ static void gc_sweep_rest(rb_objspace_t *objspace) { rb_heap_t *heap = heap_eden; /* lazy sweep only for eden */ - - if (is_lazy_sweeping(heap)) { - while (is_lazy_sweeping(heap)) { + if ((heap)->sweep_pages != NULL) { + while ((heap)->sweep_pages != NULL) { gc_sweep_step(objspace, heap); } } ~~~ English: When I tried to compile ruby with GC_ENABLE_LAZY_SWEEP=0, Ruby does not sweep objects immediatly. ~~~ $ ../configure CFLAGS="-DGC_ENABLE_LAZY_SWEEP=0" && make miniruby $ cat bug2.rb GC.disable 10000.times { Object.new } total_freed_objects1 = GC.stat[:total_freed_objects] GC.enable GC.start(full_mark: true, immediate_sweep: true) total_freed_objects2 = GC.stat[:total_freed_objects] puts "freed object : #{total_freed_objects2 - total_freed_objects1}" $ ./miniruby -v ruby 2.2.0dev (2014-10-26 trunk 48073) [x86_64-darwin14] $ ./miniruby bug2.rb freed object : 0 ~~~ In addition, when I set GC_ENABLE_LAZY_SWEEP=0 and RGENGC_CHECK_MODE=1 ruby gives me assertion error like this: ~~~ $ ./miniruby -e '10000.times { Object.new }' Assertion failed: (objspace->flags.stat == gc_stat_none), function gc_start, file ../gc.c, line 5802. [1] 91336 abort ./miniruby -e '10000.times { Object.new }' ~~~ The following patch fix this problem. ~~~ diff --git a/gc.c b/gc.c index a27cc01..979e2e0 100644 --- a/gc.c +++ b/gc.c @@ -3314,9 +3314,8 @@ static void gc_sweep_rest(rb_objspace_t *objspace) { rb_heap_t *heap = heap_eden; /* lazy sweep only for eden */ - - if (is_lazy_sweeping(heap)) { - while (is_lazy_sweeping(heap)) { + if ((heap)->sweep_pages != NULL) { + while ((heap)->sweep_pages != NULL) { gc_sweep_step(objspace, heap); } } ~~~ -- https://bugs.ruby-lang.org/