Hello.

>Because ruby's GC is conservative.

I found interesting phenomenon.

def format(num)
  num.to_s.gsub(/(\d{1,3})(?=\d{3}+$)/) { $1 + "," }
end

def count(type)
   count = 0
   capacity = 0
   ObjectSpace.each_object(type) do |o|
     count += 1
     capacity += o.capacity
   end
   puts "#{type}"
   puts "  count = #{format(count)}"
   puts "  capacity = #{format(capacity)}"
end

def pause
   GC.enable
   GC.start
   GC.disable
   count(String)
   count(Array)
   puts
   sleep 5
end

class A
  def run
    arr = []
    800000.times { arr << "d" * 7 }
    pause
   end
end

GC.disable
A.new.run
1.times { pause } # not freed
pause # but freed here

////////////////////////////////////////////////////////

I have dived into gc.c, and applied this patch.

Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.168.2.37
diff -u -w -b -p -r1.168.2.37 gc.c
--- gc.c	13 Feb 2006 09:10:53 -0000	1.168.2.37
+++ gc.c	28 Feb 2006 07:04:44 -0000
@@ -1354,6 +1354,7 @@ garbage_collect()
     setjmp(save_regs_gc_mark);
     mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
 #if STACK_GROW_DIRECTION < 0
+    printf("----------> %p %p\n", STACK_END, rb_gc_stack_start);
     rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
 #elif STACK_GROW_DIRECTION > 0
     rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);

////////////////////////////////////////////

E:\ruby-cvs\win32_1_8>miniruby \a.rb
----------> 0012FD0C 0012FFFC
----------> 0012E4C0 0012FFFC
String
  count = 800,111
  capacity = 5,602,208
Array
  count = 7
  capacity = 806,581

----------> 0012DD10 0012FFFC
String
  count = 800,116
  capacity = 5,602,275
Array
  count = 7
  capacity = 806,581

----------> 0012ED48 0012FFFC
String
  count = 113
  capacity = 2,219
Array
  count = 6
  capacity = 96

////////////////////////////////////////////

STACK_END is more far from rb_gc_stack_start on 1.times { pause }
(same thing happens on loop { pause }) this means ruby uses more stack
on block execution.

Because rb_gc_mark_locations marks all objects in the range of STACK_END to rb_gc_stack_start.
if GC.start runs inside block, block needs more stack, so more objects can be wrongly
marked as alive. (As you can see, last `pause` is outside of block, so less stack is used,
huge array goes out of stack range, it is freed)

# But I was suprised of this result. I heard conservative GC can mark dead object wrongly
# but this was a little differenct from what I expected. Maybe I'm missing something...