Can't sweep garbage object immediatly when GC_ENABLE_LAZY_SWEEP=0

Issue #10431 has been updated by Nobuyoshi N…

Backport changed from 2.0.0: UNKNOWN, 2.1: UNKNOWN to 2.0.0: DONTNEED,
2.1: DONTNEED


Bug #10431: Can’t sweep garbage object immediatly when
GC_ENABLE_LAZY_SWEEP=0

  • 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: DONTNEED, 2.1: DONTNEED

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);
        }
     }