From: "matteo.folin@... (Matteo Folin) via ruby-core" Date: 2026-10-19T15:00:47+00:00 Subject: [ruby-core:127174] [Ruby Bug#22455] Per-Ractor GC: an idle Ractor costs ~100 KB of memory (17 KB on 4.0) Issue #22455 has been reported by matteo.folin@gmail.com (Matteo Folin). ---------------------------------------- Bug #22455: Per-Ractor GC: an idle Ractor costs ~100 KB of memory (17 KB on 4.0) https://bugs.ruby-lang.org/issues/22455 * Author: matteo.folin@gmail.com (Matteo Folin) * Status: Open * ruby -v: ruby 4.1.0preview1 (2026-10-11 master 2d08b5f42f) +PRISM [aarch64-linux] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- ### Description With the per-Ractor GC, an idle Ractor (blocked in `Ractor.receive`) costs ~101 KB of RSS against ~17 KB on 4.0.7. In our server, a connection's Ractor, with a few threads and a few hundred live objects, went from ~55���80 KB on 4.0 to ~590 KB on 4.1. 25,000 connections need ~15 GB instead of ~1.4 GB. The per-Ractor GC removes our main 4.0 problem: every GC used to stop and mark all Ractors, so its pauses grew with the number of connections. A Ractor per connection is the shape it should favour. At this memory cost, that shape is hard to use for many connections. Is the floor per Ractor (heap pages per size class?) expected, and can it be lowered, for example by allocating a Ractor's pages lazily or sharing partly-used pages? ### Reproduction ```ruby # 4,000 Ractors blocked in Ractor.receive: memory each, and the cost of a full GC. Warning[:experimental] = false def rss_mb = File.read("/proc/self/status")[/VmRSS:\s+(\d+)/, 1].to_i / 1024.0 def now_ms = Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1000 GC.start base = rss_mb ractors = Array.new(4000) { Ractor.new { Ractor.receive } } sleep 1 puts format("rss per idle Ractor: %.0f KB", (rss_mb - base) * 1024 / ractors.size) 3.times do t = now_ms GC.start puts format("GC.start: %.1f ms", now_ms - t) end ``` ### Results Same machine as above. | | 4.0.7 | 4.1.0-preview1 | |---|---|---| | RSS per idle Ractor | 17 KB | 101 KB | | `GC.start` (global) with 4,000 idle Ractors | 10���21 ms | 43���141 ms | The global GC's cost matters together with Bug #22454: if global GCs are what reclaims exited Ractors, a server that holds thousands of Ractors pays this pause each time. We saw single global GCs of 0.8���3.9 s, most of it sweeping, in a server holding 2,000���5,000 connection Ractors. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/