mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-06 23:39:31 +03:00
Do not discard segments for large object allocations
This commit is contained in:
parent
0be44b2b0f
commit
8dd6460d5e
2 changed files with 46 additions and 5 deletions
|
@ -743,7 +743,7 @@ void mi_heap_drop_segment_if_required(mi_heap_t* heap, size_t alloc_block_size)
|
||||||
{
|
{
|
||||||
size_t targetSegmentCount = mi_option_get_size(mi_option_max_segments_per_heap);
|
size_t targetSegmentCount = mi_option_get_size(mi_option_max_segments_per_heap);
|
||||||
if ((targetSegmentCount > 0) &&
|
if ((targetSegmentCount > 0) &&
|
||||||
(alloc_block_size <= MI_LARGE_OBJ_SIZE_MAX) &&
|
(alloc_block_size <= MI_MEDIUM_OBJ_SIZE_MAX) &&
|
||||||
(heap->tld->segments.count >= targetSegmentCount)) {
|
(heap->tld->segments.count >= targetSegmentCount)) {
|
||||||
|
|
||||||
mi_heap_drop_segment(heap, targetSegmentCount);
|
mi_heap_drop_segment(heap, targetSegmentCount);
|
||||||
|
|
|
@ -1222,6 +1222,7 @@ static bool mi_segment_check_free(mi_segment_t* segment, size_t slices_needed, s
|
||||||
if (slice->slice_count >= slices_needed) {
|
if (slice->slice_count >= slices_needed) {
|
||||||
has_page = true;
|
has_page = true;
|
||||||
}
|
}
|
||||||
|
free_space_mask |= mi_free_space_mask_from_slicecount(slice->slice_count);
|
||||||
}
|
}
|
||||||
slice = slice + slice->slice_count;
|
slice = slice + slice->slice_count;
|
||||||
}
|
}
|
||||||
|
@ -1344,6 +1345,9 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slice
|
||||||
if (max_tries <= 0) return NULL;
|
if (max_tries <= 0) return NULL;
|
||||||
|
|
||||||
mi_segment_t* segment;
|
mi_segment_t* segment;
|
||||||
|
mi_segment_t* best_candidate_segment = NULL;
|
||||||
|
size_t best_free_space_mask = MI_FREE_SPACE_MASK_ANY;
|
||||||
|
int candidates_to_check = 5;
|
||||||
size_t free_space_mask = mi_free_space_mask_from_blocksize(block_size);
|
size_t free_space_mask = mi_free_space_mask_from_blocksize(block_size);
|
||||||
mi_arena_field_cursor_t current; _mi_arena_field_cursor_init2(heap, ¤t, free_space_mask);
|
mi_arena_field_cursor_t current; _mi_arena_field_cursor_init2(heap, ¤t, free_space_mask);
|
||||||
while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL))
|
while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL))
|
||||||
|
@ -1366,10 +1370,42 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slice
|
||||||
// found a large enough free span, or a page of the right block_size with free space
|
// found a large enough free span, or a page of the right block_size with free space
|
||||||
// we return the result of reclaim (which is usually `segment`) as it might free
|
// we return the result of reclaim (which is usually `segment`) as it might free
|
||||||
// the segment due to concurrent frees (in which case `NULL` is returned).
|
// the segment due to concurrent frees (in which case `NULL` is returned).
|
||||||
mi_segment_t* segmentToReturn = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld);
|
mi_segment_t* candidate_segment = segment;
|
||||||
if (segmentToReturn != NULL) {
|
size_t candidates_free_space_mask = segment->free_space_mask & MI_FREE_SPACE_MASK_ANY; // clear the abandoned bit
|
||||||
mi_segment_increment_reclaimed_stats();
|
|
||||||
return segmentToReturn;
|
// If the requested block size is the largest available in the segment then use this segment
|
||||||
|
if (free_space_mask > ((~free_space_mask) & candidates_free_space_mask)) {
|
||||||
|
candidate_segment = mi_segment_reclaim(candidate_segment, heap, block_size, reclaimed, tld);
|
||||||
|
if (candidate_segment != NULL) {
|
||||||
|
// Found a better candidate; return the current best candidate to the abandoned list.
|
||||||
|
if (best_candidate_segment != NULL) {
|
||||||
|
_mi_arena_segment_mark_abandoned(best_candidate_segment);
|
||||||
|
}
|
||||||
|
best_candidate_segment = candidate_segment;
|
||||||
|
// found a good candidate segment; break the serch loop.
|
||||||
|
mi_segment_increment_reclaimed_stats();
|
||||||
|
return best_candidate_segment;
|
||||||
|
}
|
||||||
|
// The current segment was freed. Look for another one.
|
||||||
|
} else if (candidates_free_space_mask < best_free_space_mask || best_candidate_segment == NULL) {
|
||||||
|
//candidate_segment = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld);
|
||||||
|
if (candidate_segment != NULL) {
|
||||||
|
// Found a better candidate; return the current best candidate to the abandoned list.
|
||||||
|
if (best_candidate_segment != NULL) {
|
||||||
|
_mi_arena_segment_mark_abandoned(best_candidate_segment);
|
||||||
|
}
|
||||||
|
best_candidate_segment = candidate_segment;
|
||||||
|
best_free_space_mask = candidates_free_space_mask;
|
||||||
|
candidate_segment = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate_segment != NULL) {
|
||||||
|
_mi_arena_segment_mark_abandoned(candidate_segment);
|
||||||
|
}
|
||||||
|
candidates_to_check--;
|
||||||
|
if (candidates_to_check == 0) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (segment->abandoned_visits > 3 && is_suitable && mi_option_get_size(mi_option_max_segments_per_heap) == 0) {
|
else if (segment->abandoned_visits > 3 && is_suitable && mi_option_get_size(mi_option_max_segments_per_heap) == 0) {
|
||||||
|
@ -1383,6 +1419,11 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (best_candidate_segment != NULL) {
|
||||||
|
mi_segment_increment_reclaimed_stats();
|
||||||
|
return mi_segment_reclaim(best_candidate_segment, heap, block_size, reclaimed, tld);
|
||||||
|
}
|
||||||
|
|
||||||
mi_segment_increment_reclaim_failed_stats();
|
mi_segment_increment_reclaim_failed_stats();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue