diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index ee7f1026..a5ca3e27 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -159,6 +159,7 @@ bool _mi_arena_page_try_reabandon_to_mapped(mi_page_t* page); // arena-meta.c void* _mi_meta_zalloc( size_t size, mi_memid_t* memid ); void _mi_meta_free(void* p, size_t size, mi_memid_t memid); +bool _mi_meta_is_meta_page(void* p); // "page-map.c" bool _mi_page_map_init(void); diff --git a/src/arena.c b/src/arena.c index 32c0b32e..a61f59b0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -162,6 +162,8 @@ void* mi_arena_area(mi_arena_id_t arena_id, size_t* size) { static mi_memid_t mi_memid_create_arena(mi_arena_t* arena, size_t slice_index, size_t slice_count) { mi_assert_internal(slice_index < UINT32_MAX); mi_assert_internal(slice_count < UINT32_MAX); + mi_assert_internal(slice_count > 0); + mi_assert_internal(slice_index < arena->slice_count); mi_memid_t memid = _mi_memid_create(MI_MEM_ARENA); memid.mem.arena.arena = arena; memid.mem.arena.slice_index = (uint32_t)slice_index; @@ -663,7 +665,8 @@ static mi_page_t* mi_arena_page_alloc_fresh(size_t slice_count, size_t block_siz page->reserved = (uint16_t)reserved; page->page_start = (uint8_t*)page + block_start; page->block_size = block_size; - page->memid = memid; + page->memid = memid; + mi_assert_internal(memid.mem.arena.slice_count > 0); page->free_is_zero = memid.initially_zero; if (block_size > 0 && _mi_is_power_of_two(block_size)) { page->block_size_shift = (uint8_t)mi_ctz(block_size); @@ -1197,7 +1200,33 @@ static size_t mi_debug_show_bfield(mi_bfield_t field, char* buf) { return bit_set_count; } -static size_t mi_debug_show_bitmap(const char* header, size_t slice_count, mi_bitmap_t* bitmap, bool invert) { +static size_t mi_debug_show_page_bfield(mi_bfield_t field, char* buf, mi_arena_t* arena, size_t slice_index) { + size_t bit_set_count = 0; + long bit_of_page = 0; + for (int bit = 0; bit < MI_BFIELD_BITS; bit++, bit_of_page--) { + bool is_set = ((((mi_bfield_t)1 << bit) & field) != 0); + void* start = mi_arena_slice_start(arena, slice_index + bit); + if (is_set) { + bit_set_count++; + mi_page_t* page = (mi_page_t*)start; + char c = 'p'; + if (mi_page_is_abandoned_mapped(page)) { c = 'a'; } + else if (mi_page_is_abandoned(page)) { c = 'f'; } + bit_of_page = (long)page->memid.mem.arena.slice_count - 1; + buf[bit] = c; + } + else { + char c = '.'; + if (bit_of_page > 0) { c = '-'; } + else if (_mi_meta_is_meta_page(start)) { c = 'm'; } + else if (slice_index + bit < arena->info_slices) { c = 'i'; } + buf[bit] = c; + } + } + return bit_set_count; +} + +static size_t mi_debug_show_bitmap(const char* header, size_t slice_count, mi_bitmap_t* bitmap, bool invert, mi_arena_t* arena) { _mi_output_message("%s:\n", header); size_t bit_count = 0; size_t bit_set_count = 0; @@ -1217,7 +1246,8 @@ static size_t mi_debug_show_bitmap(const char* header, size_t slice_count, mi_bi if (bit_count < slice_count) { mi_bfield_t bfield = chunk->bfields[j]; if (invert) bfield = ~bfield; - size_t xcount = mi_debug_show_bfield(bfield, buf + k); + size_t xcount = (arena!=NULL ? mi_debug_show_page_bfield(bfield, buf + k, arena, bit_count) + : mi_debug_show_bfield(bfield, buf + k)); if (invert) xcount = MI_BFIELD_BITS - xcount; bit_set_count += xcount; k += MI_BFIELD_BITS; @@ -1246,15 +1276,16 @@ void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[i]); if (arena == NULL) break; slice_total += arena->slice_count; - _mi_output_message("arena %zu: %zu slices (%zu MiB)%s\n", i, arena->slice_count, mi_size_of_slices(arena->slice_count)/MI_MiB, (arena->memid.is_pinned ? ", pinned" : "")); + _mi_output_message("arena %zu at %p: %zu slices (%zu MiB)%s\n", i, arena, arena->slice_count, mi_size_of_slices(arena->slice_count)/MI_MiB, (arena->memid.is_pinned ? ", pinned" : "")); if (show_inuse) { - free_total += mi_debug_show_bitmap("in-use slices", arena->slice_count, arena->slices_free, true); + free_total += mi_debug_show_bitmap("in-use slices", arena->slice_count, arena->slices_free, true, NULL); } - mi_debug_show_bitmap("committed slices", arena->slice_count, arena->slices_committed, false); + mi_debug_show_bitmap("committed slices", arena->slice_count, arena->slices_committed, false, NULL); // todo: abandoned slices if (show_purge) { - purge_total += mi_debug_show_bitmap("purgeable slices", arena->slice_count, arena->slices_purge, false); + purge_total += mi_debug_show_bitmap("purgeable slices", arena->slice_count, arena->slices_purge, false, NULL); } + mi_debug_show_bitmap("pages (p=page, a=abandoned, f=full-abandoned, i=info, m=meta)", arena->slice_count, arena->pages, false, arena); } if (show_inuse) _mi_output_message("total inuse slices : %zu\n", slice_total - free_total); // if (show_abandoned) _mi_verbose_message("total abandoned slices: %zu\n", abandoned_total); diff --git a/src/init.c b/src/init.c index 85588970..5c5186b9 100644 --- a/src/init.c +++ b/src/init.c @@ -398,11 +398,10 @@ static bool _mi_thread_heap_done(mi_heap_t* heap) { // merge stats _mi_stats_done(&heap->tld->stats); - // free if not the main thread - if (heap != &_mi_heap_main) { - _mi_meta_free(heap, sizeof(mi_heap_t), heap->memid); - } - else { + // free heap meta data + _mi_meta_free(heap, sizeof(mi_heap_t), heap->memid); + + if (heap == &_mi_heap_main) { #if 0 // never free the main thread even in debug mode; if a dll is linked statically with mimalloc, // there may still be delete/free calls after the mi_fls_done is called. Issue #207 @@ -410,6 +409,10 @@ static bool _mi_thread_heap_done(mi_heap_t* heap) { mi_assert_internal(heap->tld->heap_backing == &_mi_heap_main); #endif } + + // free the tld + mi_tld_t* tld = _mi_tld(); + _mi_meta_free(_mi_tld(), sizeof(mi_tld_t), tld->memid); return false; } diff --git a/src/page.c b/src/page.c index a90c1d7d..a30db6c9 100644 --- a/src/page.c +++ b/src/page.c @@ -82,7 +82,7 @@ static bool mi_page_is_valid_init(mi_page_t* page) { mi_assert_internal(mi_page_block_size(page) > 0); mi_assert_internal(page->used <= page->capacity); mi_assert_internal(page->capacity <= page->reserved); - + // const size_t bsize = mi_page_block_size(page); // uint8_t* start = mi_page_start(page); //mi_assert_internal(start + page->capacity*page->block_size == page->top); @@ -623,7 +623,7 @@ void _mi_page_init(mi_heap_t* heap, mi_page_t* page) { #endif mi_assert_internal(page->block_size_shift == 0 || (mi_page_block_size(page) == ((size_t)1 << page->block_size_shift))); mi_assert_expensive(mi_page_is_valid_init(page)); - + // initialize an initial free list mi_page_extend_free(heap,page); mi_assert(mi_page_immediate_available(page)); diff --git a/test/test-stress.c b/test/test-stress.c index 0488fc2b..df535e6e 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -344,12 +344,14 @@ int main(int argc, char** argv) { #ifndef USE_STD_MALLOC #ifndef NDEBUG //mi_debug_show_arenas(true, true, false); + // mi_debug_show_arenas(true, false, false); mi_collect(true); - mi_debug_show_arenas(true,true,false); - #endif - // mi_collect(true); - // mi_debug_show_arenas(true, true, false); + mi_debug_show_arenas(true, false, false); + #else + mi_collect(false); + mi_debug_show_arenas(true, true, false); // mi_stats_print(NULL); + #endif #else mi_stats_print(NULL); // so we see rss/commit/elapsed #endif