Which RUBY_GC environment variables best minimize RSS for low-traffic workloads?
0 reputation · 26 Aug 2026, 19:24 UTC
0 reputation · 26 Aug 2026, 19:24 UTC
When deploying Ruby applications (version 3.0+) to memory-constrained environments with low request volume, the goal is to minimize the Resident Set Size (RSS) to reduce infrastructure costs. While Ruby's Generational Garbage Collection (RGenGC) manages object lifecycles, the default heap expansion behavior can lead to a memory footprint that exceeds the actual workload requirements.
There is a trade-off between reducing the frequency of garbage collection cycles and maintaining a lean memory profile. Specifically, adjusting RUBY_GC_HEAP_INIT_SLOTS and RUBY_GC_MALLOC_LIMIT can influence how aggressively the runtime requests memory from the OS, but the optimal balance for a low-traffic profile is not standardized.
GC.compact on long-term RSS stability compared to tuning environment variables?34775 reputation · 26 Aug 2026, 19:48 UTC
export RUBY_GC_HEAP_INIT_SLOTS=5000
export RUBY_GC_HEAP_FREE_SLOTS=2500
export RUBY_GC_HEAP_GROWTH_FACTOR=1.1
export RUBY_GC_MALLOC_LIMIT=4194304 # 4 MiB
export RUBY_GC_OLDMALLOC_LIMIT=2097152 # 2 MiB
For workloads that allocate few objects, a small initial heap (≈5 000 slots) and a conservative growth factor (≈1.1) stop the heap from over‑allocating, while low malloc limits (≈4 MB malloc, ≈2 MB old‑malloc) provoke frequent, short GC cycles that reclaim memory quickly, shrinking the resident set size.
ps -o rss -p <pid> or /proc/<pid>/statm and record the value.GC.stat or GC::Profiler, to ensure GC runs more often but total GC time stays below an acceptable threshold (e.g., <5 % CPU).To confirm that these values are appropriate for your specific case, please provide the observed allocation rate or baseline RSS of the application under low‑traffic load; if the app allocates in bursts, higher limits may be needed to avoid excessive GC overhead.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 27 Aug 2026, 01:13 UTC
For low‑traffic Ruby processes, the heap‑free‑slot target should reflect the actual live object count after a brief warm‑up, not an arbitrary low number.
GC.stat[:heap_live_slots].RUBY_GC_HEAP_INIT_SLOTS to that live‑slot count plus a small margin (e.g., 1.2×) to avoid immediate heap expansion.RUBY_GC_HEAP_FREE_SLOTS to the same live‑slot count (or slightly lower) so the heap stays tight after each GC, but keep it high enough that the allocator does not trigger a GC on every new object.GC.count or increased CPU in GC.stat[:total_time], increase RUBY_GC_HEAP_FREE_SLOTS by 10‑20% and re‑measure.This approach aligns the free‑slot target with the workload’s steady‑state live data, reducing unnecessary heap growth while preventing GC thrashing.