https://redmine.ruby-lang.org/
https://redmine.ruby-lang.org/favicon.ico?1711330511
2010-10-13T14:27:59Z
Ruby Issue Tracking System
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13713
2010-10-13T14:27:59Z
usa (Usaku NAKAMURA)
usa@garbagecollect.jp
<ul><li><strong>Category</strong> set to <i>core</i></li><li><strong>Status</strong> changed from <i>Open</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>authorNari (Narihiro Nakamura)</i></li><li><strong>Priority</strong> changed from <i>3</i> to <i>5</i></li><li><strong>Target version</strong> set to <i>1.9.3</i></li><li><strong>ruby -v</strong> set to <i>ruby 1.9.3dev (2010-10-13 trunk 29477)</i></li></ul><p>=begin</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13725
2010-10-14T10:34:38Z
matz (Yukihiro Matsumoto)
matz@ruby.or.jp
<ul></ul><p>=begin<br>
まつもと ゆきひろです</p>
<p>In message "Re: <a href="/issues/3940">[ruby-dev:42369]</a> [BUG: trunk] Lazy sweep and ObjectSpace.each_object"<br>
on Wed, 13 Oct 2010 14:13:46 +0900, SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> writes:</p>
<p>| 解決策として、中田さんに ObjectSpace.each_object に相当する関数<br>
|rb_objspace_each_objects を実行する前に sweep を完全に終了させる、という<br>
|方法を教えてもらいました。</p>
<p>オブジェクトがsweep対象かどうかはわかるはずなんだから、sweep<br>
されるはずのものはeach_objectの対象にしない手もあるんじゃな<br>
いの? なんか勘違いしてる?</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13729
2010-10-14T19:13:47Z
ko1 (Koichi Sasada)
<ul></ul><p>=begin<br>
ささだです。</p>
<p>(2010/10/14 2:34), Yukihiro Matsumoto wrote:</p>
<blockquote>
<p>| 解決策として、中田さんに ObjectSpace.each_object に相当する関数<br>
|rb_objspace_each_objects を実行する前に sweep を完全に終了させる、という<br>
|方法を教えてもらいました。</p>
<p>オブジェクトがsweep対象かどうかはわかるはずなんだから、sweep<br>
されるはずのものはeach_objectの対象にしない手もあるんじゃな<br>
いの? なんか勘違いしてる?</p>
</blockquote>
<p> 手もあると思います。</p>
<p> ただ、 "rb_objspace_each_objects()" の仕様上、slot を callback にその<br>
まま渡すようにしているため、free / sweep 対象かは、callback 先で確認しな<br>
ければなりません。free オブジェクトかどうかは、</p>
<pre><code>flag が 0 かどうか
</code></pre>
<p>で見ることが出来ますが、sweep 対象(実質 free)であるかどうかは、</p>
<pre><code>slot が sweep_slots かつ、
mark されていないか
</code></pre>
<p>を確認しなければなりません。callback に sweep_slots かどうかを入れるのも<br>
大変だし、そもそも rb_objspace_each_objects() なんて使われるのはレアケー<br>
スだし、まー全部やっちゃえばいいか、という感じです。</p>
<p> と、今気づきましたが、rb_objspace_each_objects() の callback で GC が<br>
起きても同じ問題がありますね。callback する前で sweep を完了するように変<br>
更しても、結局問題は残るし。どうしようかな。</p>
<p> 上記 check を行う rb_objspace_live_p(VALUE) みたいなのを用意して、これ<br>
を使うようにしてもらう、とか?</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13751
2010-10-15T17:17:10Z
keiju (Keiju Ishitsuka)
keiju@ishitsuka.com
<ul></ul><p>=begin<br>
けいじゅ@いしつかです.</p>
<p>In <a href="/issues/3940">[ruby-dev:42369]</a> the message: "<a href="/issues/3940">[ruby-dev:42369]</a> [BUG: trunk] Lazy<br>
sweep and ObjectSpace.each_object", on Oct/13 14:13(JST) SASADA Koichi<br>
writes:</p>
<blockquote>
<p> ささだです。</p>
<p> Lazy sweep 中に ObjectSpace.each_object(相当)を行うと、SEGV するの<br>
で、下記のようなパッチを作成しました。</p>
</blockquote>
<p>ちょっとお聞きしたいんですけど, この問題って, どの辺りのバージョンから<br>
入っています?</p>
<p>それと, 1.9.2での話なんですが, finalizerを指定している場合プロセス終了<br>
時にSEGVすることがあるんですが, これと関係ありますでしょうか?</p>
<p>__<br>
---------------------------------------------------->> 石塚 圭樹 <<---<br>
---------------------------------->> e-mail: <a href="mailto:keiju@ishitsuka.com" class="email">keiju@ishitsuka.com</a> <<---</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13752
2010-10-15T17:27:01Z
ko1 (Koichi Sasada)
<ul></ul><p>=begin<br>
ささだです。</p>
<p>(2010/10/15 9:16), 石塚圭樹 wrote:</p>
<blockquote>
<blockquote>
<blockquote>
<p> Lazy sweep 中に ObjectSpace.each_object(相当)を行うと、SEGV するの<br>
で、下記のようなパッチを作成しました。<br>
ちょっとお聞きしたいんですけど, この問題って, どの辺りのバージョンから<br>
入っています?</p>
</blockquote>
</blockquote>
<p>それと, 1.9.2での話なんですが, finalizerを指定している場合プロセス終了<br>
時にSEGVすることがあるんですが, これと関係ありますでしょうか?</p>
</blockquote>
<p> 1.9.3 以降です。</p>
<p> 1.9.2 のほうは、別の問題かと思います。</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13757
2010-10-15T20:40:24Z
keiju (Keiju Ishitsuka)
keiju@ishitsuka.com
<ul></ul><p>=begin<br>
けいじゅ@いしつかです.</p>
<p>In <a href="https://blade.ruby-lang.org/ruby-dev/42396">[ruby-dev:42396]</a> the message: "<a href="https://blade.ruby-lang.org/ruby-dev/42396">[ruby-dev:42396]</a> Re: [BUG: trunk]<br>
Lazy sweep and ObjectSpace.each_object", on Oct/15 17:26(JST) SASADA<br>
Koichi writes:</p>
<blockquote>
<p> ささだです。</p>
</blockquote>
<blockquote>
<blockquote>
<p>ちょっとお聞きしたいんですけど, この問題って, どの辺りのバージョンから<br>
入っています?</p>
</blockquote>
<p> 1.9.3 以降です。</p>
</blockquote>
<p>そうですか, 残念.</p>
<p>ところで, 添付のようなエラーが出てSEGVしちゃうんですけど, 原因が何か分<br>
かります?</p>
<p>何をやっているかというと, 親プロセスから子プロセスをforkしていて, 子側<br>
がSEGVしています.</p>
<p>親側では, threadとかmutexを使っていて色々と非同期処理をしています.<br>
fork後, 子側でそのthreadがGCされるときに発生しているみたいなんですが...</p>
<p>非同期処理をしながらforkするところに無理があるって話もありそうなんです<br>
が...</p>
<p>それと, このバックトレースではeach_object中に発生していますが, その前<br>
に GC.start を入れると, そこで発生します.</p>
<p>-- ここから<br>
/var/projects/fairy/fairy/lib/fairy/share/base-app.rb:94: [BUG] thread_free: locking_mutex must be NULL (0x87fd5f0:138337388)<br>
ruby 1.9.1p430 (2010-08-16 revision 28998) [i686-linux]</p>
<h2>-- control frame ----------<br>
c:0015 p:0015 s:0049 b:0048 l:000031 d:000047 BLOCK /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:94<br>
c:0014 p:---- s:0045 b:0045 l:000044 d:000044 FINISH<br>
c:0013 p:---- s:0043 b:0043 l:000042 d:000042 CFUNC :each_object<br>
c:0012 p:0022 s:0039 b:0039 l:000031 d:000038 BLOCK /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:92<br>
c:0011 p:---- s:0037 b:0037 l:000036 d:000036 FINISH<br>
c:0010 p:---- s:0035 b:0035 l:000034 d:000034 CFUNC :fork<br>
c:0009 p:0035 s:0032 b:0032 l:000031 d:000031 METHOD /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:91<br>
c:0008 p:0016 s:0027 b:0027 l:000026 d:000026 METHOD /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:18<br>
c:0007 p:0080 s:0022 b:0022 l:000015 d:000021 BLOCK /var/projects/fairy/fairy/lib/fairy/master.rb:112<br>
c:0006 p:0019 s:0019 b:0019 l:000018 d:000018 METHOD <a href="internal:prelude" class="external">internal:prelude</a>:8<br>
c:0005 p:0012 s:0016 b:0016 l:000015 d:000015 METHOD /var/projects/fairy/fairy/lib/fairy/master.rb:110<br>
c:0004 p:0145 s:0013 b:0013 l:000012 d:000012 METHOD /var/projects/fairy/lib/deep-connect/evaluator.rb:32<br>
c:0003 p:0064 s:0006 b:0006 l:0023fc d:000005 BLOCK /var/projects/fairy/lib/deep-connect/session.rb:155<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:---- s:0002 b:0002 l:000001 d:000001 CONT#0 controller.rb[186] Controller[0]#block (2 levels) in terminate: TERMINATE: #2.5.3<br>
CONT#0 controller.rb[191] Controller[0]#block (2 levels) in terminate: TERMINATE: #2.6<br>
CONT#0 controller.rb[166] Controller[0]#block (2 levels) in terminate: TERMINATE: #2.3<br>
CONT#0 controller.rb[168] Controller[0]#block (2 levels) in terminate: TERMINATE: #2.4<br>
TOP</h2>
<p>-- Ruby level backtrace information-----------------------------------------<br>
/var/projects/fairy/fairy/lib/fairy/share/base-app.rb:94:in <code>block (2 levels) in start_subcommand' /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:92:in </code>each_object'<br>
/var/projects/fairy/fairy/lib/fairy/share/base-app.rb:92:in <code>block in start_subcommand' /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:91:in </code>fork'<br>
/var/projects/fairy/fairy/lib/fairy/share/base-app.rb:91:in <code>start_subcommand' /var/projects/fairy/fairy/lib/fairy/share/base-app.rb:18:in </code>start_subcommand'<br>
/var/projects/fairy/fairy/lib/fairy/master.rb:112:in <code>block in assgin_controller' <internal:prelude>:8:in </code>synchronize'<br>
[M] master.rb[80] Master#when_disconnected: MASTER: disconnected: Start terminationcts/fairy/lib/deep-connect/evaluator.rb:32:in <code>evaluate_request' /var/projects/fairy/lib/deep-connect/session.rb:155:in </code>block in receive'</p>
<p>-- C level backtrace information -------------------------------------------<br>
0x8157b71 fairy master (rb_vm_bugreport+0xa1) [0x8157b71]<br>
0x8193156 fairy master [0x8193156]<br>
0x8193208 fairy master (rb_bug+0x28) [0x8193208]<br>
0x814311d fairy master [0x814311d]<br>
0x8064e9e fairy master [0x8064e9e]<br>
0x8065339 fairy master (rb_gc_finalize_deferred+0x59) [0x8065339]<br>
0x815c2ad fairy master [0x815c2ad]<br>
0x8155fe9 fairy master [0x8155fe9]<br>
0x8148ddb fairy master [0x8148ddb]<br>
0x814f644 fairy master [0x814f644]<br>
0x8150a7f fairy master (rb_yield+0x4f) [0x8150a7f]<br>
0x80682e6 fairy master [0x80682e6]<br>
0x8143f7d fairy master [0x8143f7d]<br>
0x81440a4 fairy master [0x81440a4]<br>
0x8155f54 fairy master [0x8155f54]<br>
0x8148ddb fairy master [0x8148ddb]</p>
<p>__<br>
---------------------------------------------------->> 石塚 圭樹 <<---<br>
---------------------------------->> e-mail: <a href="mailto:keiju@ishitsuka.com" class="email">keiju@ishitsuka.com</a> <<---</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13758
2010-10-15T21:08:32Z
ko1 (Koichi Sasada)
<ul></ul><p>=begin<br>
ささだです。</p>
<p>(2010/10/15 12:40), 石塚圭樹 wrote:</p>
<blockquote>
<p>ところで, 添付のようなエラーが出てSEGVしちゃうんですけど, 原因が何か分<br>
かります?</p>
<p>何をやっているかというと, 親プロセスから子プロセスをforkしていて, 子側<br>
がSEGVしています.</p>
<p>親側では, threadとかmutexを使っていて色々と非同期処理をしています.<br>
fork後, 子側でそのthreadがGCされるときに発生しているみたいなんですが...</p>
<p>非同期処理をしながらforkするところに無理があるって話もありそうなんです<br>
が...</p>
<p>それと, このバックトレースではeach_object中に発生していますが, その前<br>
に GC.start を入れると, そこで発生します.</p>
<p>-- ここから<br>
/var/projects/fairy/fairy/lib/fairy/share/base-app.rb:94: [BUG] thread_free: locking_mutex must be NULL (0x87fd5f0:138337388)<br>
ruby 1.9.1p430 (2010-08-16 revision 28998) [i686-linux]</p>
</blockquote>
<p> さすがにこれだけでは...、と思ったけど、fork した直後に locking_mutex<br>
を空にする処理を走らせているのに、それが間に合ってない感じですかね。</p>
<p> ファイナライザで何をやっているか、などを併せて最小ケースを貰えると良い<br>
かもしれません。</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13800
2010-10-18T13:02:06Z
authorNari (Narihiro Nakamura)
authorNari@gmail.com
<ul></ul><p>=begin<br>
nariです。</p>
<p>2010年10月14日19:13 SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a>:</p>
<blockquote>
<p> ささだです。</p>
<p>(2010/10/14 2:34), Yukihiro Matsumoto wrote:</p>
<blockquote>
<p>| 解決策として、中田さんに ObjectSpace.each_object に相当する関数<br>
|rb_objspace_each_objects を実行する前に sweep を完全に終了させる、という<br>
|方法を教えてもらいました。</p>
<p>オブジェクトがsweep対象かどうかはわかるはずなんだから、sweep<br>
されるはずのものはeach_objectの対象にしない手もあるんじゃな<br>
いの? なんか勘違いしてる?</p>
</blockquote>
<p> 手もあると思います。</p>
<p>ただ、 "rb_objspace_each_objects()" の仕様上、slot を callback にその<br>
まま渡すようにしているため、free / sweep 対象かは、callback 先で確認しな<br>
ければなりません。free オブジェクトかどうかは、</p>
<pre><code> flag が 0 かどうか
</code></pre>
<p>で見ることが出来ますが、sweep 対象(実質 free)であるかどうかは、</p>
<pre><code> slot が sweep_slots かつ、
mark されていないか
</code></pre>
<p>を確認しなければなりません。callback に sweep_slots かどうかを入れるのも<br>
大変だし、そもそも rb_objspace_each_objects() なんて使われるのはレアケー<br>
スだし、まー全部やっちゃえばいいか、という感じです。</p>
<p>と、今気づきましたが、rb_objspace_each_objects() の callback で GC が<br>
起きても同じ問題がありますね。callback する前で sweep を完了するように変<br>
更しても、結局問題は残るし。どうしようかな。</p>
<p>上記 check を行う rb_objspace_live_p(VALUE) みたいなのを用意して、これ<br>
を使うようにしてもらう、とか?</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
</blockquote>
<p>rb_objspace_each_objects() の実行前には sweep を完全に終了させることに<br>
して、実行中は rb_gc_disable() して、実行後に元に戻すようにどうかなと思った<br>
のですが、いかがでしょうか?</p>
<p>--<br>
Narihiro Nakamura (nari)</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13801
2010-10-18T13:16:17Z
ko1 (Koichi Sasada)
<ul></ul><p>=begin<br>
ささだです。</p>
<p>(2010/10/18 5:01), Narihiro Nakamura wrote:</p>
<blockquote>
<p>rb_objspace_each_objects() の実行前には sweep を完全に終了させることに<br>
して、実行中は rb_gc_disable() して、実行後に元に戻すようにどうかなと思った<br>
のですが、いかがでしょうか?</p>
</blockquote>
<p> GC.enable で回避できてしまう(SEGV するパスが出来てしまう)のでまずい<br>
のではないでしょうか。</p>
<p> 少し考えてみたのですが、例えば、Lazy sweep 禁止フラグ(eager に sweep<br>
する)を設けるのはどうでしょうか。Ruby 側からは触らせないフラグにすれ<br>
ば、SEGV する危険は防ぐことが出来るのではないかと。</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13805
2010-10-18T13:35:29Z
authorNari (Narihiro Nakamura)
authorNari@gmail.com
<ul></ul><p>=begin<br>
nariです。</p>
<p>2010年10月18日13:15 SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a>:</p>
<blockquote>
<p> ささだです。</p>
<p>(2010/10/18 5:01), Narihiro Nakamura wrote:</p>
<blockquote>
<p>rb_objspace_each_objects() の実行前には sweep を完全に終了させることに<br>
して、実行中は rb_gc_disable() して、実行後に元に戻すようにどうかなと思った<br>
のですが、いかがでしょうか?</p>
</blockquote>
<p> GC.enable で回避できてしまう(SEGV するパスが出来てしまう)のでまずい<br>
のではないでしょうか。</p>
</blockquote>
<p>そうですね。</p>
<blockquote>
<p>少し考えてみたのですが、例えば、Lazy sweep 禁止フラグ(eager に sweep<br>
する)を設けるのはどうでしょうか。Ruby 側からは触らせないフラグにすれ<br>
ば、SEGV する危険は防ぐことが出来るのではないかと。</p>
</blockquote>
<p>なるほど。そのように作ってみます。</p>
<p>--<br>
Narihiro Nakamura (nari)</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13808
2010-10-18T15:14:56Z
authorNari (Narihiro Nakamura)
authorNari@gmail.com
<ul></ul><p>=begin<br>
nariです。</p>
<p>Lazy sweep 禁止フラグを作りました。<br>
反対がなければコミットしたいと思います。</p>
<p>callbackの途中でGCが呼ばれてSEGVを起こすようなコードを作成し、通ることを確認しました。<br>
make checkも通ることを確認しています。</p>
<p>確認コード:</p>
<p>loop {<br>
GC.disable<br>
10.times do<br>
a = []<br>
1000.times{ a << "" }<br>
a.dup<br>
end<br>
GC.enable<br>
ObjectSpace.each_object(Array) do |a|<br>
a.map(&:object_id)<br>
10000.times{''.dup}<br>
end<br>
}</p>
<p>パッチ:</p>
<p>diff --git a/gc.c b/gc.c<br>
index b011f4a..a9a4560 100644<br>
--- a/gc.c<br>
+++ b/gc.c<br>
@@ -332,6 +332,7 @@ typedef struct rb_objspace {<br>
} heap;<br>
struct {<br>
int dont_gc;</p>
<ul>
<li>int dont_lazy_sweep;<br>
int during_gc;<br>
} flags;<br>
struct {<br>
@@ -2040,6 +2041,17 @@ lazy_sweep(rb_objspace_t *objspace)<br>
return FALSE;<br>
}</li>
</ul>
<p>+static void<br>
+rest_sweep(rb_objspace_t *objspace)<br>
+{</p>
<ul>
<li>if (objspace->heap.sweep_slots) {</li>
<li>
<pre><code> while (objspace->heap.sweep_slots) {
</code></pre>
</li>
<li>
<pre><code> lazy_sweep(objspace);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> after_gc_sweep(objspace);
</code></pre>
</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>static void gc_marks(rb_objspace_t *objspace);</p>
<p>static int<br>
@@ -2047,6 +2059,9 @@ gc_lazy_sweep(rb_objspace_t *objspace)<br>
{<br>
int res;</p>
<ul>
<li>
<p>if (objspace->flags.dont_lazy_sweep)</p>
</li>
<li>
<pre><code> return garbage_collect(objspace);
</code></pre>
</li>
<li>
<p>INIT_GC_PROF_PARAMS;</p>
<p>if (!ready_to_gc(objspace)) return TRUE;<br>
@@ -2536,6 +2551,9 @@ rb_objspace_each_objects(int (*callback)(void<br>
*vstart, void *vend,<br>
rb_objspace_t *objspace = &rb_objspace;<br>
volatile VALUE v;</p>
</li>
<li>
<p>rest_sweep(objspace);</p>
</li>
<li>
<p>objspace->flags.dont_lazy_sweep = TRUE;</p>
</li>
<li>
<p>i = 0;<br>
while (i < heaps_used) {<br>
while (0 < i && (uintptr_t)membase <<br>
(uintptr_t)objspace->heap.sorted[i-1].slot->membase)<br>
@@ -2562,6 +2580,7 @@ rb_objspace_each_objects(int (*callback)(void<br>
*vstart, void *vend,<br>
}<br>
}</p>
</li>
<li>
<p>objspace->flags.dont_lazy_sweep = FALSE;<br>
return;<br>
}</p>
</li>
</ul>
<p>--<br>
Narihiro Nakamura (nari)</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13820
2010-10-18T23:54:43Z
ko1 (Koichi Sasada)
<ul></ul><p>=begin<br>
ささだです。</p>
<p>(2010/10/18 7:14), Narihiro Nakamura wrote:</p>
<blockquote>
<p>Lazy sweep 禁止フラグを作りました。<br>
反対がなければコミットしたいと思います。</p>
<p>callbackの途中でGCが呼ばれてSEGVを起こすようなコードを作成し、通ることを確認しました。<br>
make checkも通ることを確認しています。</p>
</blockquote>
<p> これだと、例えば例外が出た場合、dont_lazy_sweep が TRUE のままになって<br>
しまうような気がします。ensure で囲まないと。</p>
<a name="余談"></a>
<h1 >余談<a href="#余談" class="wiki-anchor">¶</a></h1>
<p> ちょっと関係ないですが、gc_lazy_sweep() という関数は、下記の挙動だと思<br>
うのですが;</p>
<p>・もし、遅延した slot があれば、sweep をする<br>
これで、freelist が NULL でなければ、ここで終わり<br>
・GC を開始(mark)<br>
・遅延 sweep をして、結果を返す</p>
<p>sweep という関数で mark までしちゃうのはいいでしょうか。</p>
<p> あまり、対案はないのですが、なんとなく、garbage_collect() を 今の<br>
gc_lazy_sweep() として、今の garbage_collect() を、<br>
garbage_collect_eager() みたいにしてしまうのはどうだろう、と思いました。</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13826
2010-10-19T14:55:05Z
authorNari (Narihiro Nakamura)
authorNari@gmail.com
<ul></ul><p>=begin<br>
nariです。</p>
<blockquote>
<p> これだと、例えば例外が出た場合、dont_lazy_sweep が TRUE のままになって<br>
しまうような気がします。ensure で囲まないと。</p>
</blockquote>
<p>ぉぉ、そうですね…。ご指摘ありがとうございます。<br>
そのようなパッチを作ってみました。本メールの一番最後に貼り付けておきます。</p>
<blockquote>
<a name="余談"></a>
<h1 >余談<a href="#余談" class="wiki-anchor">¶</a></h1>
<p>ちょっと関係ないですが、gc_lazy_sweep() という関数は、下記の挙動だと思<br>
うのですが;</p>
<p>・もし、遅延した slot があれば、sweep をする<br>
これで、freelist が NULL でなければ、ここで終わり<br>
・GC を開始(mark)<br>
・遅延 sweep をして、結果を返す</p>
<p>sweep という関数で mark までしちゃうのはいいでしょうか。</p>
</blockquote>
<p>なるほど。<br>
関数名にgc_というプレフィクスが付いているので、マークしてもいいのかなと<br>
か、そういう言い訳を思いついたのですがやっぱりダメですね。</p>
<blockquote>
<p>あまり、対案はないのですが、なんとなく、garbage_collect() を 今の<br>
gc_lazy_sweep() として、今の garbage_collect() を、<br>
garbage_collect_eager() みたいにしてしまうのはどうだろう、と思いました。</p>
</blockquote>
<p>garbage_collect_eager() よりも garbage_collect_full() の方が馴染み<br>
があるのかなと思いました。こちらの方も暇を見つけて直しておきます。</p>
<p>パッチ:<br>
diff --git a/gc.c b/gc.c<br>
index b011f4a..ad49fd5 100644<br>
--- a/gc.c<br>
+++ b/gc.c<br>
@@ -332,6 +332,7 @@ typedef struct rb_objspace {<br>
} heap;<br>
struct {<br>
int dont_gc;</p>
<ul>
<li>int dont_lazy_sweep;<br>
int during_gc;<br>
} flags;<br>
struct {<br>
@@ -2040,6 +2041,17 @@ lazy_sweep(rb_objspace_t *objspace)<br>
return FALSE;<br>
}</li>
</ul>
<p>+static void<br>
+rest_sweep(rb_objspace_t *objspace)<br>
+{</p>
<ul>
<li>if (objspace->heap.sweep_slots) {</li>
<li>
<pre><code> while (objspace->heap.sweep_slots) {
</code></pre>
</li>
<li>
<pre><code> lazy_sweep(objspace);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> after_gc_sweep(objspace);
</code></pre>
</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>static void gc_marks(rb_objspace_t *objspace);</p>
<p>static int<br>
@@ -2047,6 +2059,9 @@ gc_lazy_sweep(rb_objspace_t *objspace)<br>
{<br>
int res;</p>
<ul>
<li>
<p>if (objspace->flags.dont_lazy_sweep)</p>
</li>
<li>
<pre><code> return garbage_collect(objspace);
</code></pre>
</li>
<li>
<p>INIT_GC_PROF_PARAMS;</p>
<p>if (!ready_to_gc(objspace)) return TRUE;<br>
@@ -2489,6 +2504,55 @@ Init_heap(void)<br>
init_heap(&rb_objspace);<br>
}</p>
</li>
<li>
</ul>
<p>+static VALUE<br>
+lazy_sweep_enable(void)<br>
+{</p>
<ul>
<li>rb_objspace_t *objspace = &rb_objspace;</li>
<li>
<li>objspace->flags.dont_lazy_sweep = FALSE;</li>
<li>return Qnil;<br>
+}</li>
<li>
</ul>
<p>+static VALUE<br>
+objspace_each_objects(VALUE arg)<br>
+{</p>
<ul>
<li>size_t i;</li>
<li>RVALUE *membase = 0;</li>
<li>RVALUE *pstart, *pend;</li>
<li>rb_objspace_t *objspace = &rb_objspace;</li>
<li>VALUE *args = (VALUE *)arg;</li>
<li>volatile VALUE v;</li>
<li>
<li>i = 0;</li>
<li>while (i < heaps_used) {</li>
<li>while (0 < i && (uintptr_t)membase <<br>
(uintptr_t)objspace->heap.sorted[i-1].slot->membase)</li>
<li>
<pre><code> i--;
</code></pre>
</li>
<li>while (i < heaps_used &&<br>
(uintptr_t)objspace->heap.sorted[i].slot->membase <=<br>
(uintptr_t)membase )</li>
<li>
<pre><code> i++;
</code></pre>
</li>
<li>if (heaps_used <= i)</li>
<li>break;</li>
<li>membase = objspace->heap.sorted[i].slot->membase;</li>
<li>
<li>pstart = objspace->heap.sorted[i].slot->slot;</li>
<li>pend = pstart + objspace->heap.sorted[i].slot->limit;</li>
<li>
<li>for (; pstart != pend; pstart++) {</li>
<li>
<pre><code> if (pstart->as.basic.flags) {
</code></pre>
</li>
<li>
<pre><code> v = (VALUE)pstart; /* acquire to save this object */
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>}</li>
<li>if (pstart != pend) {</li>
<li>
<pre><code> if ((*(int (*)(void *, void *, size_t, void *))args[0])(pstart,
</code></pre>
</li>
</ul>
<p>pend, sizeof(RVALUE), (void *)args[1])) {</p>
<ul>
<li>
<pre><code> return;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>
<li>return Qnil;<br>
+}</li>
<li>
</ul>
<p>/*</p>
<ul>
<li>rb_objspace_each_objects() is special C API to walk through</li>
<li>Ruby object space. This C API is too difficult to use it.<br>
@@ -2530,39 +2594,15 @@ rb_objspace_each_objects(int (*callback)(void<br>
*vstart, void *vend,<br>
size_t stride, void *d),<br>
void *data)<br>
{</li>
</ul>
<ul>
<li>size_t i;</li>
<li>RVALUE *membase = 0;</li>
<li>RVALUE *pstart, *pend;</li>
</ul>
<ul>
<li>VALUE args[2];<br>
rb_objspace_t *objspace = &rb_objspace;</li>
</ul>
<ul>
<li>
<p>volatile VALUE v;</p>
</li>
<li>
<li>
<p>i = 0;</p>
</li>
<li>
<p>while (i < heaps_used) {</p>
</li>
<li>
<p>while (0 < i && (uintptr_t)membase <<br>
(uintptr_t)objspace->heap.sorted[i-1].slot->membase)</p>
</li>
<li>
<pre><code> i--;
</code></pre>
</li>
<li>
<p>while (i < heaps_used &&<br>
(uintptr_t)objspace->heap.sorted[i].slot->membase <=<br>
(uintptr_t)membase )</p>
</li>
<li>
<pre><code> i++;
</code></pre>
</li>
<li>
<p>if (heaps_used <= i)</p>
</li>
<li>
<p>break;</p>
</li>
<li>
<p>membase = objspace->heap.sorted[i].slot->membase;</p>
</li>
<li>
<p>pstart = objspace->heap.sorted[i].slot->slot;</p>
</li>
<li>
<p>pend = pstart + objspace->heap.sorted[i].slot->limit;</p>
</li>
<li>
<li>
<p>for (; pstart != pend; pstart++) {</p>
</li>
<li>
<pre><code> if (pstart->as.basic.flags) {
</code></pre>
</li>
<li>
<pre><code> v = (VALUE)pstart; /* acquire to save this object */
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<p>}</p>
</li>
<li>
<p>if (pstart != pend) {</p>
</li>
<li>
<pre><code> if ((*callback)(pstart, pend, sizeof(RVALUE), data)) {
</code></pre>
</li>
<li>
<pre><code> return;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<p>}</p>
</li>
<li>
<p>}</p>
</li>
</ul>
<ul>
<li>rest_sweep(objspace);</li>
<li>objspace->flags.dont_lazy_sweep = TRUE;</li>
</ul>
<ul>
<li>return;</li>
</ul>
<ul>
<li>args[0] = (VALUE)callback;</li>
<li>args[1] = (VALUE)data;</li>
<li>rb_ensure(objspace_each_objects, (VALUE)args, lazy_sweep_enable, Qnil);<br>
}</li>
</ul>
<p>struct os_each_struct {</p>
<p>--<br>
Narihiro Nakamura (nari)</p>
<p>=end</p>
Ruby master - Bug #3940: Lazy sweep and ObjectSpace.each_object
https://redmine.ruby-lang.org/issues/3940?journal_id=13835
2010-10-21T13:27:06Z
Anonymous
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>=begin<br>
This issue was solved with changeset r29543.<br>
Koichi, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<p>=end</p>