[BUG: trunk] Lazy sweep and ObjectSpace.each_object

$B!!$5$5$@$G$9!#(B

$B!!(BLazy sweep $BCf$K(B
ObjectSpace.each_object$B!JAjEv!K$r9T$&$H!"(BSEGV $B$9$k$N(B
$B$G!"2<5-$N$h$&$J%Q%C%A$r:n@.$7$^$7$?!#(B

32bit $B4D6-$N(B test-all $B$G!":G6a(B sdbm $B$G(B SEGV

$B$7$F$?$N$OB?J,$3$l$,LdBj!#(B

ObjectSpace.each_object $B$r;H$C$F$$$k$N$G!#(B

$B!!?dB,$G$9$,!"2<5-$N$h$&$J860x$G$O$J$$$+$H;W$$$^$9!#(B

(1) GC mark $B=N;;~!"%%V%8%’%/%H(B o1 $B$H!"$=$3$+$i;2>H$5$l$k(B o2
$B$,(B
mark $B$5$l$:!"(Bsweep $BBP>]$K$J$k(B
(2) lazy sweep $B$K$h$j!"(Bo2 $B$,2s<}$5$l$k(B
(3) ObjectSpace.each_object $B$K$h$j!"(Bo1 $B$X%"%/%;%9$9$k(B
(4) o1 $B$+$i(B o2 $B$r;2>H$7$h$&$H$7$F(B SEGV

$B!!2r7h:v$H$7$F!“CfED$5$s$K(B ObjectSpace.each_object
$B$KAjEv$9$k4X?t(B
rb_objspace_each_objects $B$r<B9T$9$kA0$K(B sweep
$B$r40A4$K=*N;$5$;$k!”$H$$$&(B
$BJ}K!$r65$($F$b$i$$$^$7$?!#(B

$B!!%P%0$N3NG’%3!<%I$H%Q%C%A$r$*Aw$j$7$^$9!#$b$7!"E,Ev$G$7$?$i<h$j9~$s$GD:(B
$B$1$k$H9,$$$G$9!#(B

$B3NG’%3!<%I!’(B

loop{
cls = (0…10_000).map{Class.new}
cls.each{|c| c.new}
ObjectSpace.each_object{|e| e.object_id; ‘’}
}

$B%Q%C%A!’(B

Index: gc.c

— gc.c (revision 29471)
+++ gc.c (working copy)
@@ -2040,6 +2040,17 @@
return FALSE;
}

+static void
+rest_sweep(rb_objspace_t *objspace)
+{

  • if (objspace->heap.sweep_slots) {
  • while (objspace->heap.sweep_slots) {
  •  lazy_sweep(objspace);
    
  • }
  • after_gc_sweep(objspace);
  • }
    +}

static void gc_marks(rb_objspace_t *objspace);

static int
@@ -2536,6 +2547,8 @@
rb_objspace_t *objspace = &rb_objspace;
volatile VALUE v;

  • rest_sweep(objspace);
  • i = 0;
    while (i < heaps_used) {
    while (0 < i && (uintptr_t)membase <
    (uintptr_t)objspace->heap.sorted[i-1].slot->membase)

$B$^$D$b$H(B $B$f$-$R$m$G$9(B

In message “Re: [ruby-dev:42369] [BUG: trunk] Lazy sweep and
ObjectSpace.each_object”
on Wed, 13 Oct 2010 14:13:46 +0900, SASADA Koichi [email protected]
writes:

|$B!!2r7h:v$H$7$F!“CfED$5$s$K(B ObjectSpace.each_object $B$KAjEv$9$k4X?t(B
|rb_objspace_each_objects $B$r<B9T$9$kA0$K(B sweep $B$r40A4$K=*N;$5$;$k!”$H$$$&(B
|$BJ}K!$r65$($F$b$i$$$^$7$?!#(B

$B%%V%8%'%/%H$,(Bsweep$BBP>]$+$I$&$+$O$o$+$k$O$:$J$s$@$+$i!“(Bsweep
$B$5$l$k$O$:$N$b$N$O(Beach_object$B$NBP>]$K$7$J$$<j$b$”$k$s$8$c$J(B
$B$$$N!)(B $B$J$s$+4
0c$$$7$F$k!)(B

$B!!$5$5$@$G$9!#(B

(2010/10/14 2:34), Yukihiro M. wrote:

|$B!!2r7h:v$H$7$F!“CfED$5$s$K(B ObjectSpace.each_object $B$KAjEv$9$k4X?t(B
|rb_objspace_each_objects $B$r<B9T$9$kA0$K(B sweep
$B$r40A4$K=*N;$5$;$k!”$H$$$&(B
|$BJ}K!$r65$($F$b$i$$$^$7$?!#(B

$B%%V%8%’%/%H$,(Bsweep$BBP>]$+$I$&$+$O$o$+$k$O$:$J$s$@$+$i!"(Bsweep
$B$5$l$k$O$:$N$b$N$O(Beach_object$B$NBP>]$K$7$J$$<j$b$"$k$s$8$c$J(B
$B$$$N!)(B $B$J$s$+4
0c$$$7$F$k!)(B

$B!!<j$b$"$k$H;W$$$^$9!#(B

$B!!$?$@!"(B “rb_objspace_each_objects()” $B$N;EMM>e!"(Bslot $B$r(B
callback $B$K$=$N(B
$B$^$^EO$9$h$&$K$7$F$$$k$?$a!"(Bfree / sweep $BBP>]$+$O!"(Bcallback
$B@h$G3NG’$7$J(B
$B$1$l$P$J$j$^$;$s!#(Bfree $B%*%V%8%’%/%H$+$I$&$+$O!"(B

flag $B$,(B 0 $B$+$I$&$+(B

$B$G8+$k$3$H$,=PMh$^$9$,!"(Bsweep $BBP>]!J<B<A(B
free$B!K$G$"$k$+$I$&$+$O!"(B

slot $B$,(B sweep_slots $B$+$D!"(B
mark $B$5$l$F$$$J$$$+(B

$B$r3NG’$7$J$1$l$P$J$j$^$;$s!#(Bcallback $B$K(B sweep_slots
$B$+$I$&$+$rF~$l$k$N$b(B
$BBgJQ$@$7!"$=$b$=$b(B rb_objspace_each_objects()
$B$J$s$F;H$o$l$k$N$O%l%"%1!<(B
$B%9$@$7!"$^!<A4It$d$C$A$c$($P$$$$$+!"$H$$$&46$8$G$9!#(B

$B!!$H!":#5$$E$-$^$7$?$,!"(Brb_objspace_each_objects() $B$N(B callback
$B$G(B GC $B$,(B
$B5/$-$F$bF1$8LdBj$,$"$j$^$9$M!#(Bcallback $B$9$kA0$G(B sweep
$B$r40N;$9$k$h$&$KJQ(B
$B99$7$F$b!"7k6ILdBj$O;D$k$7!#$I$&$7$h$&$+$J!#(B

$B!!>e5-(B check $B$r9T$&(B rb_objspace_live_p(VALUE)
$B$_$?$$$J$N$rMQ0U$7$F!"$3$l(B
$B$r;H$&$h$&$K$7$F$b$i$&!"$H$+!)(B

nari$B$G$9!#(B

2010$BG/(B10$B7n(B14$BF|(B19:13 SASADA Koichi [email protected]:

   slot $B$,(B sweep_slots $B$+$D!"(B

$B>e5-(B check $B$r9T$&(B rb_objspace_live_p(VALUE)
$B$_$?$$$J$N$rMQ0U$7$F!“$3$l(B
$B$r;H$&$h$&$K$7$F$b$i$&!”$H$+!)(B


// SASADA Koichi at atdot dot net

rb_objspace_each_objects() $B$N<B9TA0$K$O(B sweep
$B$r40A4$K=*N;$5$;$k$3$H$K(B
$B$7$F!“<B9TCf$O(B rb_gc_disable()
$B$7$F!”<B9T8e$K85$KLa$9$h$&$K$I$&$+$J$H;W$C$?(B
$B$N$G$9$,!"$$$+$,$G$7$g$&$+!)(B

nari$B$G$9!#(B

2010$BG/(B10$B7n(B18$BF|(B13:15 SASADA Koichi [email protected]:

$B!!$5$5$@$G$9!#(B

(2010/10/18 5:01), Narihiro N. wrote:

rb_objspace_each_objects() $B$N<B9TA0$K$O(B sweep $B$r40A4$K=*N;$5$;$k$3$H$K(B
$B$7$F!“<B9TCf$O(B rb_gc_disable()
$B$7$F!”<B9T8e$K85$KLa$9$h$&$K$I$&$+$J$H;W$C$?(B
$B$N$G$9$,!"$$$+$,$G$7$g$&$+!)(B

$B!!(BGC.enable $B$G2sHr$G$-$F$7$^$&!J(BSEGV
$B$9$k%Q%9$,=PMh$F$7$^$&!K$N$G$^$:$$(B
$B$N$G$O$J$$$G$7$g$&$+!#(B

$B$=$&$G$9$M!#(B

$B>/$79M$($F$$?$N$G$9$,!“Nc$($P!”(BLazy sweep $B6X;%U%i%0!J(Beager $B$K(B
sweep
$B$9$k!K$r@_$1$k$N$O$I$&$G$7$g$&$+!#(BRuby $BB&$+$i$O?($i$;$J$$%U%i%0$K$9$l(B
$B$P!"(BSEGV $B$9$k4m81$OKI$0$3$H$,=PMh$k$N$G$O$J$$$+$H!#(B

$B$J$k$[$I!#$=$N$h$&$K:n$C$F$_$^$9!#(B

$B!!$5$5$@$G$9!#(B

(2010/10/18 5:01), Narihiro N. wrote:

rb_objspace_each_objects() $B$N<B9TA0$K$O(B sweep $B$r40A4$K=*N;$5$;$k$3$H$K(B
$B$7$F!"<B9TCf$O(B rb_gc_disable()
$B$7$F!"<B9T8e$K85$KLa$9$h$&$K$I$&$+$J$H;W$C$?(B
$B$N$G$9$,!"$$$+$,$G$7$g$&$+!)(B

$B!!(BGC.enable $B$G2sHr$G$-$F$7$^$&!J(BSEGV
$B$9$k%Q%9$,=PMh$F$7$^$&!K$N$G$^$:$$(B
$B$N$G$O$J$$$G$7$g$&$+!#(B

$B!!>/$79M$($F$$?$N$G$9$,!“Nc$($P!”(BLazy sweep $B6X;%U%i%0!J(Beager
$B$K(B sweep
$B$9$k!K$r@_$1$k$N$O$I$&$G$7$g$&$+!#(BRuby
$BB&$+$i$O?($i$;$J$$%U%i%0$K$9$l(B
$B$P!"(BSEGV $B$9$k4m81$OKI$0$3$H$,=PMh$k$N$G$O$J$$$+$H!#(B

nari$B$G$9!#(B

Lazy sweep $B6X;%U%i%0$r:n$j$^$7$?!#(B
$BH?BP$,$J$1$l$P%3%
%C%H$7$?$$$H;W$$$^$9!#(B

callback$B$NESCf$G(BGC$B$,8F$P$l$F(BSEGV$B$r5/$3$9$h$&$J%3!<%I$r:n@.$7!"DL$k$3$H$r3NG’$7$^$7$?!#(B
make check$B$bDL$k$3$H$r3NG’$7$F$$$^$9!#(B

$B3NG’%3!<%I(B:

loop {
GC.disable
10.times do
a = []
1000.times{ a << “” }
a.dup
end
GC.enable
ObjectSpace.each_object(Array) do |a|
a.map(&:object_id)
10000.times{’’.dup}
end
}

$B%Q%C%A(B:

diff --git a/gc.c b/gc.c
index b011f4a…a9a4560 100644
— a/gc.c
+++ b/gc.c
@@ -332,6 +332,7 @@ typedef struct rb_objspace {
} heap;
struct {
int dont_gc;

  • int dont_lazy_sweep;
    int during_gc;
    } flags;
    struct {
    @@ -2040,6 +2041,17 @@ lazy_sweep(rb_objspace_t *objspace)
    return FALSE;
    }

+static void
+rest_sweep(rb_objspace_t *objspace)
+{

  • if (objspace->heap.sweep_slots) {
  •   while (objspace->heap.sweep_slots) {
    
  •       lazy_sweep(objspace);
    
  •   }
    
  •   after_gc_sweep(objspace);
    
  • }
    +}

static void gc_marks(rb_objspace_t *objspace);

static int
@@ -2047,6 +2059,9 @@ gc_lazy_sweep(rb_objspace_t *objspace)
{
int res;

  • if (objspace->flags.dont_lazy_sweep)

  •    return garbage_collect(objspace);
    
  • INIT_GC_PROF_PARAMS;

    if (!ready_to_gc(objspace)) return TRUE;
    @@ -2536,6 +2551,9 @@ rb_objspace_each_objects(int (*callback)(void
    *vstart, void *vend,
    rb_objspace_t *objspace = &rb_objspace;
    volatile VALUE v;

  • rest_sweep(objspace);

  • objspace->flags.dont_lazy_sweep = TRUE;

  • i = 0;
    while (i < heaps_used) {
    while (0 < i && (uintptr_t)membase <
    (uintptr_t)objspace->heap.sorted[i-1].slot->membase)
    @@ -2562,6 +2580,7 @@ rb_objspace_each_objects(int (*callback)(void
    *vstart, void *vend,
    }
    }

  • objspace->flags.dont_lazy_sweep = FALSE;
    return;
    }

$B!!$5$5$@$G$9!#(B

(2010/10/18 7:14), Narihiro N. wrote:

Lazy sweep $B6X;%U%i%0$r:n$j$^$7$?!#(B
$BH?BP$,$J$1$l$P%3%
%C%H$7$?$$$H;W$$$^$9!#(B

callback$B$NESCf$G(BGC$B$,8F$P$l$F(BSEGV$B$r5/$3$9$h$&$J%3!<%I$r:n@.$7!"DL$k$3$H$r3NG’$7$^$7$?!#(B

make check$B$bDL$k$3$H$r3NG’$7$F$$$^$9!#(B

$B!!$3$l$@$H!“Nc$($PNc30$,=P$?>l9g!”(Bdont_lazy_sweep $B$,(B TRUE
$B$N$^$^$K$J$C$F(B
$B$7$^$&$h$&$J5$$,$7$^$9!#(Bensure $B$G0O$^$J$$$H!#(B

$BM>CL(B

$B!!$A$g$C$H4X78$J$$$G$9$,!"(Bgc_lazy_sweep()
$B$H$$$&4X?t$O!"2<5-$N5sF0$@$H;W(B
$B$&$N$G$9$,!((B

$B!&$b$7!“CY1d$7$?(B slot $B$,$”$l$P!"(Bsweep $B$r$9$k(B
$B!!$3$l$G!"(Bfreelist $B$,(B NULL $B$G$J$1$l$P!"$3$3$G=*$o$j(B
$B!&(BGC $B$r3+;O!J(Bmark$B!K(B
$B!&CY1d(B sweep $B$r$7$F!"7k2L$rJV$9(B

sweep $B$H$$$&4X?t$G(B mark $B$^$G$7$A$c$&$N$O$$$$$G$7$g$&$+!#(B

$B!!$"$^$j!“BP0F$O$J$$$N$G$9$,!”$J$s$H$J$/!"(Bgarbage_collect() $B$r(B
$B:#$N(B
gc_lazy_sweep() $B$H$7$F!":#$N(B garbage_collect() $B$r!"(B
garbage_collect_eager()
$B$_$?$$$K$7$F$7$^$&$N$O$I$&$@$m$&!"$H;W$$$^$7$?!#(B

nari$B$G$9!#(B

$B!!$3$l$@$H!“Nc$($PNc30$,=P$?>l9g!”(Bdont_lazy_sweep $B$,(B TRUE
$B$N$^$^$K$J$C$F(B
$B$7$^$&$h$&$J5$$,$7$^$9!#(Bensure $B$G0O$^$J$$$H!#(B

$B$)$)!"$=$&$G$9$M!D!#$4;XE&$"$j$,$H$&$4$6$$$^$9!#(B
$B$=$N$h$&$J%Q%C%A$r:n$C$F$_$^$7$?!#K%a!<%k$N0lHV:G8e$KE=$jIU$1$F$*$-$^$9!#(B

sweep $B$H$$$&4X?t$G(B mark $B$^$G$7$A$c$&$N$O$$$$$G$7$g$&$+!#(B

$B$J$k$[$I!#(B
$B4X?tL>$K(Bgc_$B$H$$$&%W%l%U%#%/%9$,IU$$$F$$$k$N$G!"%^!<%/$7$F$b$$$$$N$+$J$H(B
$B$+!"$=$&$$$&8@$$Lu$r;W$$$D$$$?$N$G$9$,$d$C$Q$j%@%a$G$9$M!#(B

$B$"$^$j!“BP0F$O$J$$$N$G$9$,!”$J$s$H$J$/!"(Bgarbage_collect() $B$r(B $B:#$N(B
gc_lazy_sweep() $B$H$7$F!":#$N(B garbage_collect() $B$r!"(B
garbage_collect_eager() $B$_$?$$$K$7$F$7$^$&$N$O$I$&$@$m$&!"$H;W$$$^$7$?!#(B

garbage_collect_eager() $B$h$j$b(B garbage_collect_full()
$B$NJ}$,Fk@w$_(B
$B$,$"$k$N$+$J$H;W$$$^$7$?!#$3$A$i$NJ}$b2K$r8+$D$1$FD>$7$F$*$-$^$9!#(B

$B%Q%C%A(B:
diff --git a/gc.c b/gc.c
index b011f4a…ad49fd5 100644
— a/gc.c
+++ b/gc.c
@@ -332,6 +332,7 @@ typedef struct rb_objspace {
} heap;
struct {
int dont_gc;

  • int dont_lazy_sweep;
    int during_gc;
    } flags;
    struct {
    @@ -2040,6 +2041,17 @@ lazy_sweep(rb_objspace_t *objspace)
    return FALSE;
    }

+static void
+rest_sweep(rb_objspace_t *objspace)
+{

  • if (objspace->heap.sweep_slots) {
  •   while (objspace->heap.sweep_slots) {
    
  •       lazy_sweep(objspace);
    
  •   }
    
  •   after_gc_sweep(objspace);
    
  • }
    +}

static void gc_marks(rb_objspace_t *objspace);

static int
@@ -2047,6 +2059,9 @@ gc_lazy_sweep(rb_objspace_t *objspace)
{
int res;

  • if (objspace->flags.dont_lazy_sweep)

  •    return garbage_collect(objspace);
    
  • INIT_GC_PROF_PARAMS;

    if (!ready_to_gc(objspace)) return TRUE;
    @@ -2489,6 +2504,55 @@ Init_heap(void)
    init_heap(&rb_objspace);
    }

+static VALUE
+lazy_sweep_enable(void)
+{

  • rb_objspace_t *objspace = &rb_objspace;
  • objspace->flags.dont_lazy_sweep = FALSE;
  • return Qnil;
    +}

+static VALUE
+objspace_each_objects(VALUE arg)
+{

  • size_t i;
  • RVALUE *membase = 0;
  • RVALUE *pstart, *pend;
  • rb_objspace_t *objspace = &rb_objspace;
  • VALUE *args = (VALUE *)arg;
  • volatile VALUE v;
  • i = 0;
  • while (i < heaps_used) {
  • while (0 < i && (uintptr_t)membase <
    (uintptr_t)objspace->heap.sorted[i-1].slot->membase)
  •  i--;
    
  • while (i < heaps_used &&
    (uintptr_t)objspace->heap.sorted[i].slot->membase <=
    (uintptr_t)membase )
  •  i++;
    
  • if (heaps_used <= i)
  • break;
  • membase = objspace->heap.sorted[i].slot->membase;
  • pstart = objspace->heap.sorted[i].slot->slot;
  • pend = pstart + objspace->heap.sorted[i].slot->limit;
  • for (; pstart != pend; pstart++) {
  •  if (pstart->as.basic.flags) {
    
  • v = (VALUE)pstart; /* acquire to save this object */
  • break;
  •  }
    
  • }
  • if (pstart != pend) {
  •  if ((*(int (*)(void *, void *, size_t, void *))args[0])(pstart,
    

pend, sizeof(RVALUE), (void *)args[1])) {

  • return;
  •  }
    
  • }
  • }
  • return Qnil;
    +}

/*

  • rb_objspace_each_objects() is special C API to walk through
  • Ruby object space. This C API is too difficult to use it.
    @@ -2530,39 +2594,15 @@ rb_objspace_each_objects(int (*callback)(void
    *vstart, void *vend,
    size_t stride, void *d),
    void *data)
    {
  • size_t i;
  • RVALUE *membase = 0;
  • RVALUE *pstart, *pend;
  • VALUE args[2];
    rb_objspace_t *objspace = &rb_objspace;
  • volatile VALUE v;

  • i = 0;

  • while (i < heaps_used) {

  • while (0 < i && (uintptr_t)membase <
    (uintptr_t)objspace->heap.sorted[i-1].slot->membase)

  •  i--;
    
  • while (i < heaps_used &&
    (uintptr_t)objspace->heap.sorted[i].slot->membase <=
    (uintptr_t)membase )

  •  i++;
    
  • if (heaps_used <= i)

  • break;

  • membase = objspace->heap.sorted[i].slot->membase;

  • pstart = objspace->heap.sorted[i].slot->slot;

  • pend = pstart + objspace->heap.sorted[i].slot->limit;

  • for (; pstart != pend; pstart++) {

  •  if (pstart->as.basic.flags) {
    
  • v = (VALUE)pstart; /* acquire to save this object */

  • break;

  •  }
    
  • }

  • if (pstart != pend) {

  •  if ((*callback)(pstart, pend, sizeof(RVALUE), data)) {
    
  • return;

  •  }
    
  • }

  • }

  • rest_sweep(objspace);
  • objspace->flags.dont_lazy_sweep = TRUE;
  • return;
  • args[0] = (VALUE)callback;
  • args[1] = (VALUE)data;
  • rb_ensure(objspace_each_objects, (VALUE)args, lazy_sweep_enable,
    Qnil);
    }

struct os_each_struct {

$B%A%1%C%H(B #3940 $B$,99?7$5$l$^$7$?!#(B (by Anonymous)

$B%9%F!<%?%9(B Assigned$B$+$i(BClosed$B$KJQ99(B
$B?JD=(B % 0$B$+$i(B100$B$KJQ99(B

This issue was solved with changeset r29543.
Koichi, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.