Thanks for bug report and benchmarking the performance over time! I found a bug that causes thrashing in heap page allocation: https://github.com/ruby/ruby/pull/6156.
Before this patch:
ruby 3.2.0dev (2022-07-20T16:32:04Z pz-bug-18929 b25ee69e38) [arm64-darwin21]
ruby -ve '50000000.times { Object.new }' 4.34s user 0.13s system 99% cpu 4.517 total
After this patch:
ruby 3.2.0dev (2022-07-20T12:40:31Z pz-bug-18929 86d061294d) [arm64-darwin21]
ruby -ve '50000000.times { Object.new }' 3.48s user 0.05s system 99% cpu 3.547 total
Ruby 3.1:
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]
ruby -ve '50000000.times { Object.new }' 3.43s user 0.06s system 99% cpu 3.489 total
Before this commit, if we don't have enough slots after sweeping but
had pages on the tomb heap, then the GC would frequently allocate and
deallocate pages. This is because after sweeping it would set
allocatable pages (since there were not enough slots) but free the
pages on the tomb heap.
This commit reuses pages on the tomb heap if there's not enough slots
after sweeping.