From 8d57336360497e94403a71bd13de8faa76f1dbcb Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Wed, 8 Jun 2022 11:05:53 -0400 Subject: [PATCH] Fix major GC thrashing Only growth heaps are allowed to start major GCs. Before this patch, growth heaps are defined as size pools that freed more slots than had empty slots (i.e. there were more dead objects that empty space). But if the size pool is relatively stable and tightly packed with mostly old objects and has allocatable pages, then it would be incorrectly classified as a growth heap and trigger major GC. But since it's stable, it would not use any of the allocatable pages and forever be classified as a growth heap, causing major GC thrashing. This commit changes the definition of growth heap to require that the size pool to have no allocatable pages. --- gc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 42e0da8d09..42ccae0d11 100644 --- a/gc.c +++ b/gc.c @@ -5684,9 +5684,11 @@ gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool) bool grow_heap = is_full_marking(objspace); if (!is_full_marking(objspace)) { - /* The heap is a growth heap if it freed more slots than had empty slots. */ - bool is_growth_heap = size_pool->empty_slots == 0 || - size_pool->freed_slots > size_pool->empty_slots; + /* The heap is a growth heap if it freed more slots than had empty + * slots and used up all of its allocatable pages. */ + bool is_growth_heap = (size_pool->empty_slots == 0 || + size_pool->freed_slots > size_pool->empty_slots) && + size_pool->allocatable_pages == 0; if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) { grow_heap = TRUE;