Feature #18494


[RFC] ENV["RUBY_GC_..."]= changes GC parameters dynamically

Added by normalperson (Eric Wong) 5 months ago. Updated 5 months ago.

Target version:


This is intended to give Ruby application developers a way to to
improve the out-of-the-box experience for end users running
tools written in Ruby. In most cases, end users are not and
cannot be expected to know how to tune the GC better than the
developers who wrote the Ruby code.

This has no extra API footprint, and will silently be a no-op
for other Ruby implementations.

One potential incompatibility is users doing something like:

ENV["RUBY_GC_..."] = "1m"

However, the different behavior would be largely innocuous aside from
different performance characteristics in the parent process. Using:

system({ "RUBY_GC_..." => "1m" }, ...)

...would restore the previous behavior (and is generally the
preferred usage, anyways, to avoid thread-safety issues).

RFC since I've only tested this with RUBY_GC_MALLOC_LIMIT and
RUBY_GC_MALLOC_LIMIT_MAX, so far. I've yet to check Ractor
interactions since haven't followed Ruby in several years.

I made this change to reduce memory use in a single-threaded
pipeline+process manager designed for audio playback; but it
probably makes sense for many long-running daemons that want
to clamp memory use after all code is loaded.

Note: I can't create Redmine tickets due to MFA: [ruby-core:105878].
I completely disagree with MFA for Open Source contributions as it's a
needless barrier to participation. Open Source worked fine for decades
without MFA. I show you my code and even explain my changes; but nobody
here knows me and nobody ever will. I don't want nor need anyone to
trust me when they can read my code and even ask me to clarify things
if needed.

 hash.c               | 5 +++++
 test/ruby/test_gc.rb | 4 ++++
 2 files changed, 9 insertions(+)
 diff --git a/hash.c b/hash.c
 index f032ef642a..d7cc797ef5 100644
 --- a/hash.c
 +++ b/hash.c
 @@ -4911,6 +4911,7 @@ static VALUE env_aset(VALUE nm, VALUE val);
 static void
 reset_by_modified_env(const char *nam)
 +    static char gc_var_pfx[] = "RUBY_GC_";
  * ENV['TZ'] = nil has a special meaning.
  * TZ is no longer considered up-to-date and ruby call tzset() as needed.
 @@ -4919,6 +4920,10 @@ reset_by_modified_env(const char *nam)
 if (ENVMATCH(nam, TZ_ENV)) {
 +    } else if (ENVNMATCH(nam, gc_var_pfx, sizeof(gc_var_pfx) - 1)) {
 +        ENV_LOCK();
 +        ruby_gc_set_params();
 +        ENV_UNLOCK();
 diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
 index 788f2974b5..5fd5924fb3 100644
 --- a/test/ruby/test_gc.rb
 +++ b/test/ruby/test_gc.rb
 @@ -334,6 +334,10 @@ def test_gc_parameter
 assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_MAX=16000000/, "")
 assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=2.0/, "")
 +    assert_in_out_err(["-w", "-e", <<-'end'], "", [], /RUBY_GC_MALLOC_LIMIT=1024/, "")
 +      ENV['RUBY_GC_MALLOC_LIMIT'] = '1k'
 +    end
 def test_profiler_enabled



Also available in: Atom PDF