diff options
author | Peter Zhu <peter@peterzhu.ca> | 2025-08-08 15:04:48 -0400 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2025-08-08 16:04:11 -0400 |
commit | e639e5fd1af51e2462879d6db862ee5320914ba7 (patch) | |
tree | ecbc46850de700a7eada3cbe56b38b1bd853d630 | |
parent | 0ba488d7f51c8b52811445245c87cb824e564069 (diff) |
Make rb_gc_impl_writebarrier_remember Ractor-safe
rb_gc_impl_writebarrier_remember is not Ractor safe because it writes to
bitmaps and also pushes onto the mark stack during incremental marking.
We should acquire the VM lock to prevent race conditions.
In the case that the object is not old, there is no performance impact.
However, we can see a performance impact in this microbenchmark where the
object is old:
4.times.map do
Ractor.new do
ary = []
3.times { GC.start }
10_000_000.times do |i|
ary.push(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)
ary.clear
end
end
end.map(&:value)
Before:
Time (mean ± σ): 682.4 ms ± 5.1 ms [User: 2564.8 ms, System: 16.0 ms]
After:
Time (mean ± σ): 5.522 s ± 0.096 s [User: 8.237 s, System: 7.931 s]
Co-Authored-By: Luke Gruber <luke.gruber@shopify.com>
Co-Authored-By: John Hawthorn <john@hawthorn.email>
-rw-r--r-- | gc/default/default.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/gc/default/default.c b/gc/default/default.c index 9038a01e4e..d4e34b9d03 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -6110,15 +6110,19 @@ rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj) gc_report(1, objspace, "rb_gc_writebarrier_remember: %s\n", rb_obj_info(obj)); - if (is_incremental_marking(objspace)) { - if (RVALUE_BLACK_P(objspace, obj)) { - gc_grey(objspace, obj); - } - } - else { - if (RVALUE_OLD_P(objspace, obj)) { - rgengc_remember(objspace, obj); + if (is_incremental_marking(objspace) || RVALUE_OLD_P(objspace, obj)) { + int lev = RB_GC_VM_LOCK_NO_BARRIER(); + { + if (is_incremental_marking(objspace)) { + if (RVALUE_BLACK_P(objspace, obj)) { + gc_grey(objspace, obj); + } + } + else if (RVALUE_OLD_P(objspace, obj)) { + rgengc_remember(objspace, obj); + } } + RB_GC_VM_UNLOCK_NO_BARRIER(lev); } } |