diff --git a/gc.c b/gc.c index b9ca9c11fa..15faf4df3c 100644 --- a/gc.c +++ b/gc.c @@ -1713,45 +1713,34 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj gc_report(3, objspace, "heap_page_add_freeobj: add %p to freelist\n", (void *)obj); } -static inline bool +static inline void heap_add_freepage(rb_heap_t *heap, struct heap_page *page) { asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); GC_ASSERT(page->free_slots != 0); + GC_ASSERT(page->freelist != NULL); - if (page->freelist) { - page->free_next = heap->free_pages; - heap->free_pages = page; + page->free_next = heap->free_pages; + heap->free_pages = page; - RUBY_DEBUG_LOG("page:%p freelist:%p", page, page->freelist); + RUBY_DEBUG_LOG("page:%p freelist:%p", page, page->freelist); - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); - return true; - } - else { - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); - return false; - } + asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); } #if GC_ENABLE_INCREMENTAL_MARK -static inline int +static inline void heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page) { asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); - if (page->freelist) { - page->free_next = heap->pooled_pages; - heap->pooled_pages = page; - objspace->rincgc.pooled_slots += page->free_slots; - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + GC_ASSERT(page->free_slots != 0); + GC_ASSERT(page->freelist != NULL); - return TRUE; - } - else { - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + page->free_next = heap->pooled_pages; + heap->pooled_pages = page; + objspace->rincgc.pooled_slots += page->free_slots; - return FALSE; - } + asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); } #endif @@ -5060,20 +5049,7 @@ gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap) rb_ractor_t *r = NULL; list_for_each(&GET_VM()->ractor.set, r, vmlr_node) { - struct heap_page *page = r->newobj_cache.using_page; - RVALUE *freelist = r->newobj_cache.freelist; - RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", page, freelist); - - if (page && freelist) { - RVALUE **p = &page->freelist; - while (*p) { - p = &(*p)->as.free.next; - } - *p = freelist; - } - - r->newobj_cache.using_page = NULL; - r->newobj_cache.freelist = NULL; + rb_gc_ractor_newobj_cache_clear(&r->newobj_cache); } } @@ -5146,21 +5122,18 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap) else if (free_slots > 0) { #if GC_ENABLE_INCREMENTAL_MARK if (need_pool) { - if (heap_add_poolpage(objspace, heap, sweep_page)) { - need_pool = FALSE; - } + heap_add_poolpage(objspace, heap, sweep_page); + need_pool = FALSE; } else { - if (heap_add_freepage(heap, sweep_page)) { - swept_slots += free_slots; - if (swept_slots > 2048) { - break; - } + heap_add_freepage(heap, sweep_page); + swept_slots += free_slots; + if (swept_slots > 2048) { + break; } } #else - heap_add_freepage(heap, sweep_page); - break; + heap_add_freepage(heap, sweep_page); #endif } else { @@ -7978,6 +7951,37 @@ rb_obj_gc_flags(VALUE obj, ID* flags, size_t max) /* GC */ +void +rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache) +{ + struct heap_page *page = newobj_cache->using_page; + RVALUE *freelist = newobj_cache->freelist; + RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", page, freelist); + + if (page && freelist) { + asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + if (page->freelist) { + RVALUE *p = page->freelist; + asan_unpoison_object((VALUE)p, false); + while (p->as.free.next) { + RVALUE *prev = p; + p = p->as.free.next; + asan_poison_object((VALUE)prev); + asan_unpoison_object((VALUE)p, false); + } + p->as.free.next = freelist; + asan_poison_object((VALUE)p); + } + else { + page->freelist = freelist; + } + asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + } + + newobj_cache->using_page = NULL; + newobj_cache->freelist = NULL; +} + void rb_gc_force_recycle(VALUE obj) { @@ -8007,7 +8011,7 @@ rb_gc_force_recycle(VALUE obj) } else { #endif - if (is_old || !GET_HEAP_PAGE(obj)->flags.before_sweep) { + if (is_old || GET_HEAP_PAGE(obj)->flags.before_sweep) { CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj); } CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj); diff --git a/internal/gc.h b/internal/gc.h index a602f0c9b3..d439f6d8f6 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -61,6 +61,11 @@ struct rb_objspace; /* in vm_core.h */ rb_obj_write((VALUE)(a), UNALIGNED_MEMBER_ACCESS((VALUE *)(slot)), \ (VALUE)(b), __FILE__, __LINE__) +typedef struct ractor_newobj_cache { + struct RVALUE *freelist; + struct heap_page *using_page; +} rb_ractor_newobj_cache_t; + /* gc.c */ extern VALUE *ruby_initial_gc_stress_ptr; extern int ruby_disable_gc; @@ -100,6 +105,7 @@ void rb_gc_mark_vm_stack_values(long n, const VALUE *values); void *ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); void *ruby_sized_xrealloc2(void *ptr, size_t new_count, size_t element_size, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); void ruby_sized_xfree(void *x, size_t size); +void rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache); RUBY_SYMBOL_EXPORT_END MJIT_SYMBOL_EXPORT_BEGIN diff --git a/ractor.c b/ractor.c index 452a2ac445..df9cbc307a 100644 --- a/ractor.c +++ b/ractor.c @@ -1443,6 +1443,9 @@ vm_remove_ractor(rb_vm_t *vm, rb_ractor_t *cr) } vm->ractor.cnt--; + /* Clear the cached freelist to prevent a memory leak. */ + rb_gc_ractor_newobj_cache_clear(&cr->newobj_cache); + ractor_status_set(cr, ractor_terminated); } RB_VM_UNLOCK(); diff --git a/ractor_core.h b/ractor_core.h index 2516277f4f..1ed6858c9f 100644 --- a/ractor_core.h +++ b/ractor_core.h @@ -138,10 +138,7 @@ struct rb_ractor_struct { VALUE verbose; VALUE debug; - struct { - struct RVALUE *freelist; - struct heap_page *using_page; - } newobj_cache; + rb_ractor_newobj_cache_t newobj_cache; // gc.c rb_objspace_reachable_objects_from struct gc_mark_func_data_struct { diff --git a/version.h b/version.h index f23e4a4ca0..9cd2aef871 100644 --- a/version.h +++ b/version.h @@ -12,7 +12,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 3 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 111 +#define RUBY_PATCHLEVEL 112 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 7