aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2022-06-08 11:05:53 -0400
committerPeter Zhu <peter@peterzhu.ca>2022-06-08 12:09:19 -0400
commit8d57336360497e94403a71bd13de8faa76f1dbcb (patch)
treeeb56f4504cb2618a3dec37a63740d2b448fb07d6
parent08a6ec341ec69c1ba60e1f6e1f69ad7485c7c2d5 (diff)
downloadruby-8d57336360497e94403a71bd13de8faa76f1dbcb.tar.gz
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.
-rw-r--r--gc.c8
1 files 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;