RUBY_DEBUG=gc_stress [FATAL] failed to allocate memory

e$B%3%s%Q%$%k;~$Ke(B RUBY_DEBUG_ENV e$B$H$$$&%^%/%m$rDj5A$7$F$*$/$H!"e(B
RUBY_DEBUG e$B$H$$$&4D6-JQ?t$,M-8z$K$J$C$F!"e(B
e$B:G=i$N:G=i$+$ie(B GC.stress e$B$r??$K$G$-$?$j$9$k$N$G$9$,!"e(B
e$B8=:_$O0J2<$N$h$&$K$&$^$/F0$-$^$;$s!#e(B

% RUBY_DEBUG=gc_stress ./ruby -e ‘p GC.stress’
[FATAL] failed to allocate memory

e$B$3$NLdBj$O!"e(BInit_native_thread() e$B$,8F$P$l$kA0$Ke(B GC
e$B$,5/$-!"e(B
garbage_collect_with_gvl() e$B$NCf$Ne(B ruby_thread_has_gvl_p()
e$B$,56$K$J$k$N$,e(B
e$B860x$G$9!#e(B

e$B2r7h$9$k$K$Oe(B Init_native_thread e$B$r$b$C$HAa$/e(B
(e$B:G=i$N%a%b%j3NJ]$h$jA0$Ke(B)
e$B8F$Y$P$$$$$O$:$G!"0J2<$N$h$&$K$7$F$b$$$$$G$7$g$&$+!#e(B

e$B$J$*!"4D6-JQ?t$G@_Dj$G$-$k$He(B rubyspec e$B$re(B GC.stress = true
e$B$G<B9T$9$k$J$I$Ke(B
e$BJXMx$G$9!#e(B

% svn diff --diff-cmd diff -x ‘-u -p’
Index: thread.c

— thread.c (revision 28173)
+++ thread.c (working copy)
@@ -4239,7 +4239,6 @@ Init_Thread(void)
rb_define_method(rb_cThread, “add_trace_func”,
thread_add_trace_func_m, 1);

 /* init thread core */
  • Init_native_thread();
    {
    /* main thread setting */
    {
    Index: vm.c
    ===================================================================
    — vm.c (revision 28173)
    +++ vm.c (working copy)
    @@ -2110,6 +2110,8 @@ struct rb_objspace *rb_objspace_alloc(vo
    #endif
    void ruby_thread_init_stack(rb_thread_t *th);

+extern void Init_native_thread(void);
+
void
Init_BareVM(void)
{
@@ -2130,6 +2132,7 @@ Init_BareVM(void)
#endif
ruby_current_vm = vm;

  • Init_native_thread();
    th_init2(th, 0);
    th->vm = vm;
    ruby_thread_init_stack(th);
    Index: thread_pthread.c
    ===================================================================
    — thread_pthread.c (revision 28173)
    +++ thread_pthread.c (working copy)
    @@ -163,7 +163,7 @@ ruby_thread_set_native(rb_thread_t *th)
    return pthread_setspecific(ruby_native_thread_key, th) == 0;
    }

-static void
+void
Init_native_thread(void)
{
rb_thread_t *th = GET_THREAD();
Index: thread_win32.c

— thread_win32.c (revision 28173)
+++ thread_win32.c (working copy)
@@ -44,7 +44,7 @@ ruby_thread_set_native(rb_thread_t *th)
return TlsSetValue(ruby_native_thread_key, th);
}

-static void
+void
Init_native_thread(void)
{
rb_thread_t *th = GET_THREAD();

2010/06/05 20:43 “Tanaka A.” [email protected]:

コンパイル時に RUBY_DEBUG_ENV というマクロを定義しておくと、
RUBY_DEBUG という環境変数が有効になって、
最初の最初から GC.stress を真にできたりするのですが、
現在は以下のようにうまく動きません。

% RUBY_DEBUG=gc_stress ./ruby -e ‘p GC.stress’
[FATAL] failed to allocate memory

この問題は、Init_native_thread() が呼ばれる前に GC が起き、
garbage_collect_with_gvl() の中の ruby_thread_has_gvl_p() が偽になるのが
åŽŸå› ã§ã™ã€‚

解決するには Init_native_thread をもっと早く (最初のメモリ確保より前に)
呼べばいいはずで、以下のようにしてもいいでしょうか。

なお、環境変数で設定できると rubyspec を GC.stress = true で実行するなどに
便利です。

% svn diff --diff-cmd diff -x ‘-u -p’
Index: thread.c

— thread.c (revision 28173)
+++ thread.c (working copy)
@@ -4239,7 +4239,6 @@ Init_Thread(void)
rb_define_method(rb_cThread, “add_trace_func”,
thread_add_trace_func_m,
1);

/* init thread core */
  • Init_native_thread();
    {
    /* main thread setting */
    {
    Index: vm.c
    ===================================================================
    — vm.c (revision 28173)
    +++ vm.c (working copy)
    @@ -2110,6 +2110,8 @@ struct rb_objspace *rb_objspace_alloc(vo
    #endif
    void ruby_thread_init_stack(rb_thread_t *th);

+extern void Init_native_thread(void);
+
void
Init_BareVM(void)
{
@@ -2130,6 +2132,7 @@ Init_BareVM(void)
#endif
ruby_current_vm = vm;

  • Init_native_thread();
    th_init2(th, 0);
    th->vm = vm;
    ruby_thread_init_stack(th);
    Index: thread_pthread.c
    ===================================================================
    — thread_pthread.c (revision 28173)
    +++ thread_pthread.c (working copy)
    @@ -163,7 +163,7 @@ ruby_thread_set_native(rb_thread_t *th)
    return pthread_setspecific(ruby_native_thread_key, th) == 0;
    }

-static void
+void
Init_native_thread(void)
{
rb_thread_t *th = GET_THREAD();
Index: thread_win32.c

— thread_win32.c (revision 28173)
+++ thread_win32.c (working copy)
@@ -44,7 +44,7 @@ ruby_thread_set_native(rb_thread_t *th)
return TlsSetValue(ruby_native_thread_key, th);
}

-static void
+void
Init_native_thread(void)
{
rb_thread_t *th = GET_THREAD();

e$B?70f$G$9!#e(B

e$B$9$_$^$;$s!#%a!<%i$N8mA`:n$G0UL#$N$J$$%a!<%k$rAw?.$7$F$7$^$$$^$7$?!#e(B
e$B$sG/$V$j$N%a!<%k$,$3$s$J$N$G?=$7Lu$"$j$^$;$s!#e(B

e$B$J$+$@$G$9!#e(B

At Sat, 5 Jun 2010 20:42:24 +0900,
Tanaka A. wrote in [ruby-dev:41536]:

e$B2r7h$9$k$K$Oe(B Init_native_thread e$B$r$b$C$HAa$/e(B (e$B:G=i$N%a%b%j3NJ]$h$jA0$Ke(B)
e$B8F$Y$P$$$$$O$:$G!"0J2<$N$h$&$K$7$F$b$$$$$G$7$g$&$+!#e(B

e$BJ9$$$?$h$&$JOC$@$J$H;W$C$?$i!"e(Bmvme$B%V%i%s%A$GF1$8$3$H$r$7$F$$$^$7$?!#e(B