summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2023-08-28 16:34:27 -0400
committerPeter Zhu <peter@peterzhu.ca>2023-08-28 18:01:29 -0400
commitfd0df1f8c6845671c86eddd85c9bcced30501690 (patch)
tree5e402dc35fdbfe5b089f1dd55eaf2db21ca4ea3c /test/ruby
parent5485680244bc40a9dba52e468fc5705973f2f5bd (diff)
Fix growth in minor GC when we have initial slots
If initial slots is set, then during a minor GC, if we have allocatable pages but the heap is mostly full, then we will set `grow_heap` to true since `total_slots` does not count allocatable pages so it will be less than `init_slots`. This can cause `allocatable_pages` to grow to much higher than desired since it will appear that the heap is mostly full.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/8310
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_gc.rb39
1 files changed, 39 insertions, 0 deletions
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index c5a9731f8a..8fc511331e 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -492,6 +492,45 @@ class TestGc < Test::Unit::TestCase
assert_in_epsilon(SIZES[i], total_slots, 0.01, s)
end
RUBY
+
+ # Check that we don't grow the heap in minor GC if we have alloctable pages.
+ env["RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO"] = "0.3"
+ env["RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO"] = "0.99"
+ env["RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO"] = "1.0"
+ env["RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR"] = "100" # Large value to disable major GC
+ assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY)
+ SIZES = #{sizes}
+
+ # Run a major GC to clear out dead objects.
+ GC.start
+
+ # Disable GC so we can control when GC is ran.
+ GC.disable
+
+ # Run minor GC enough times so that we don't grow the heap because we
+ # haven't yet ran RVALUE_OLD_AGE minor GC cycles.
+ GC::INTERNAL_CONSTANTS[:RVALUE_OLD_AGE].times { GC.start(full_mark: false) }
+
+ # Fill size pool 0 to over 50% full so that the number of allocatable
+ # pages that will be created will be over the number in heap_allocatable_pages
+ # (calculated using RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO).
+ # 70% was chosen here to guarantee that.
+ ary = []
+ while GC.stat_heap(0, :heap_allocatable_pages) >
+ (GC.stat_heap(0, :heap_allocatable_pages) + GC.stat_heap(0, :heap_eden_pages)) * 0.3
+ ary << Object.new
+ end
+
+ GC.start(full_mark: false)
+
+ # Check that we still have the same number of slots as initially configured.
+ GC.stat_heap.each do |i, s|
+ # Sometimes pages will have 1 less slot due to alignment, so always increase slots_per_page by 1.
+ slots_per_page = (s[:heap_eden_slots] / s[:heap_eden_pages]) + 1
+ total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page
+ assert_in_epsilon(SIZES[i], total_slots, 0.01, s)
+ end
+ RUBY
end
def test_profiler_enabled