purge segments on forced collect (issue #878)

This commit is contained in:
Daan 2024-04-19 12:29:49 -07:00
commit 35658681e9
3 changed files with 13 additions and 15 deletions

View File

@ -149,7 +149,7 @@ mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t pag
void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld);
void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld);
bool _mi_segment_try_reclaim_abandoned( mi_heap_t* heap, bool try_all, mi_segments_tld_t* tld);
void _mi_segment_thread_collect(mi_segments_tld_t* tld);
void _mi_segment_collect(mi_segment_t* segment, bool force, mi_segments_tld_t* tld);
#if MI_HUGE_PAGE_ABANDON
void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block);

View File

@ -104,6 +104,10 @@ static bool mi_heap_page_collect(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t
// still used blocks but the thread is done; abandon the page
_mi_page_abandon(page, pq);
}
if (collect == MI_FORCE) {
mi_segment_t* segment = _mi_page_segment(page);
_mi_segment_collect(segment, true /* force? */, &heap->tld->segments);
}
return true; // don't break
}
@ -157,12 +161,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)
// collect abandoned segments (in particular, purge expired parts of segments in the abandoned segment list)
// note: forced purge can be quite expensive if many threads are created/destroyed so we do not force on abandonment
_mi_abandoned_collect(heap, collect == MI_FORCE /* force? */, &heap->tld->segments);
// collect segment local caches
if (force) {
_mi_segment_thread_collect(&heap->tld->segments);
}
// if forced, collect thread data cache on program-exit (or shared library unload)
if (force && _mi_is_main_thread() && mi_heap_is_backing(heap)) {
_mi_thread_data_collect(); // collect thread data cache

View File

@ -404,13 +404,6 @@ static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) {
_mi_arena_free(segment, mi_segment_size(segment), csize, segment->memid, tld->stats);
}
// called by threads that are terminating
void _mi_segment_thread_collect(mi_segments_tld_t* tld) {
MI_UNUSED(tld);
// nothing to do
}
/* -----------------------------------------------------------
Commit/Decommit ranges
----------------------------------------------------------- */
@ -573,7 +566,7 @@ static void mi_segment_schedule_purge(mi_segment_t* segment, uint8_t* p, size_t
}
static void mi_segment_try_purge(mi_segment_t* segment, bool force, mi_stats_t* stats) {
if (!segment->allow_purge || mi_commit_mask_is_empty(&segment->purge_mask)) return;
if (!segment->allow_purge || segment->purge_expire == 0 || mi_commit_mask_is_empty(&segment->purge_mask)) return;
mi_msecs_t now = _mi_clock_now();
if (!force && now < segment->purge_expire) return;
@ -595,6 +588,12 @@ static void mi_segment_try_purge(mi_segment_t* segment, bool force, mi_stats_t*
mi_assert_internal(mi_commit_mask_is_empty(&segment->purge_mask));
}
// called from `mi_heap_collect_ex`
// this can be called per-page so it is important that try_purge has fast exit path
void _mi_segment_collect(mi_segment_t* segment, bool force, mi_segments_tld_t* tld) {
MI_UNUSED(force); MI_UNUSED(tld);
mi_segment_try_purge(segment, force, tld->stats);
}
/* -----------------------------------------------------------
Span free