From 05243452efd861e872a6d5c612c23a2cdea86ec5 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 8 Nov 2019 20:04:31 -0800 Subject: gc: free heaps that become empty. On glibc, our heap allocation requests are considered large and handled via mmap; when we free a heap, the memory is returned to the OS via munmap. * gc.c (sweep): If every object in a heap is freed, we free the entire heap, taking care to also reset the free list to the state before those objects were added to it. The free list may still contain objects from that same heap that were not just added to it (they were freed in a previous GC pass), so we must walk the free list to find the remaining objects and remove them. The Valgrind debugging logic (opening access and closing while walking the list) was too cumbersome so it's done in two passes: open access to the whole free list, process it, close off what is left. --- gc.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'gc.c') diff --git a/gc.c b/gc.c index 93a91267..8e84af01 100644 --- a/gc.c +++ b/gc.c @@ -607,7 +607,7 @@ static int sweep_one(obj_t *block) static int_ptr_t sweep(void) { int_ptr_t free_count = 0; - heap_t *heap; + heap_t **pph; #if HAVE_VALGRIND const int vg_dbg = opt_vg_debug; #endif @@ -632,8 +632,11 @@ static int_ptr_t sweep(void) #endif - for (heap = heap_list; heap != 0; heap = heap->next) { + for (pph = &heap_list; *pph != 0; ) { obj_t *block, *end; + heap_t *heap = *pph; + int_ptr_t old_count = free_count; + val old_free_list = free_list; #if HAVE_VALGRIND if (vg_dbg) @@ -646,6 +649,42 @@ static int_ptr_t sweep(void) { free_count += sweep_one(block); } + + if (free_count - old_count == HEAP_SIZE) { + val *ppf; + + free_list = old_free_list; +#if HAVE_VALGRIND + if (vg_dbg) { + val iter; + for (iter = free_list; iter; iter = iter->t.next) + VALGRIND_MAKE_MEM_DEFINED(iter, sizeof *iter); + } +#endif + for (ppf = &free_list; *ppf != nil; ) { + val block = *ppf; + if (block >= heap->block && block < end) { + *ppf = block->t.next; + } else { + ppf = &block->t.next; + } + } + if (free_list == 0) + free_tail = &free_list; + *pph = heap->next; + free(heap); +#if HAVE_VALGRIND + if (vg_dbg) { + val iter, next; + for (iter = free_list; iter; iter = next) { + next = iter->t.next; + VALGRIND_MAKE_MEM_NOACCESS(iter, sizeof *iter); + } + } +#endif + } else { + pph = &(*pph)->next; + } } return free_count; -- cgit v1.2.3