diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 991e8a3e..0ecc3057 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -139,6 +139,7 @@ uint8_t _mi_bin(size_t size); // for stats void _mi_heap_destroy_pages(mi_heap_t* heap); void _mi_heap_collect_abandon(mi_heap_t* heap); void _mi_heap_set_default_direct(mi_heap_t* heap); +void _mi_heap_destroy_all(void); // "stats.c" void _mi_stats_done(mi_stats_t* stats); diff --git a/include/mimalloc.h b/include/mimalloc.h index 1b7d6dd1..1fc10b2a 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -335,6 +335,7 @@ typedef enum mi_option_e { mi_option_max_errors, mi_option_max_warnings, mi_option_max_segment_reclaim, + mi_option_destroy_on_exit, _mi_option_last } mi_option_t; diff --git a/src/heap.c b/src/heap.c index c36a9616..3c73d935 100644 --- a/src/heap.c +++ b/src/heap.c @@ -327,7 +327,20 @@ void mi_heap_destroy(mi_heap_t* heap) { } } - +void _mi_heap_destroy_all(void) { + mi_heap_t* bheap = mi_heap_get_backing(); + mi_heap_t* curr = bheap->tld->heaps; + while (curr != NULL) { + mi_heap_t* next = curr->next; + if (curr->no_reclaim) { + mi_heap_destroy(curr); + } + else { + _mi_heap_destroy_pages(curr); + } + curr = next; + } +} /* ----------------------------------------------------------- Safe Heap delete diff --git a/src/init.c b/src/init.c index 8a4316e5..750693c0 100644 --- a/src/init.c +++ b/src/init.c @@ -598,7 +598,7 @@ static void mi_cdecl mi_process_done(void) { #if defined(_WIN32) && !defined(MI_SHARED_LIB) FlsFree(mi_fls_key); // call thread-done on all threads (except the main thread) to prevent dangling callback pointer if statically linked with a DLL; Issue #208 #endif - + #ifndef MI_SKIP_COLLECT_ON_EXIT #if (MI_DEBUG != 0) || !defined(MI_SHARED_LIB) // free all memory if possible on process exit. This is not needed for a stand-alone process @@ -608,6 +608,11 @@ static void mi_cdecl mi_process_done(void) { #endif #endif + if (mi_option_is_enabled(mi_option_destroy_on_exit)) { + _mi_heap_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) + _mi_mem_collect(&_mi_heap_main_get()->tld->os); // release all regions + } + if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { mi_stats_print(NULL); } diff --git a/src/options.c b/src/options.c index c5d56380..4fa5d5f8 100644 --- a/src/options.c +++ b/src/options.c @@ -93,7 +93,8 @@ static mi_option_desc_t options[_mi_option_last] = { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose { 16, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output { 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output - { 8, UNINIT, MI_OPTION(max_segment_reclaim)} // max. number of segment reclaims from the abandoned segments per try. + { 8, UNINIT, MI_OPTION(max_segment_reclaim)},// max. number of segment reclaims from the abandoned segments per try. + { 0, UNINIT, MI_OPTION(destroy_on_exit)} // release all OS memory on process exit; careful with dangling pointer or after-exit frees! }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/test/main-override-static.c b/test/main-override-static.c index a5088d3a..d216a330 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -32,7 +32,7 @@ int main() { // invalid_free(); // test_reserved(); // negative_stat(); - test_heap_walk(); + // test_heap_walk(); // alloc_huge(); void* p1 = malloc(78);