Free previously allocated memory with a given id.
| 391 | |
| 392 | // Free previously allocated memory with a given id. |
| 393 | void _mi_mem_free(void* p, size_t size, size_t alignment, size_t align_offset, size_t id, bool full_commit, bool any_reset, mi_os_tld_t* tld) { |
| 394 | mi_assert_internal(size > 0 && tld != NULL); |
| 395 | if (p==NULL) return; |
| 396 | if (size==0) return; |
| 397 | size = _mi_align_up(size, _mi_os_page_size()); |
| 398 | |
| 399 | size_t arena_memid = 0; |
| 400 | mi_bitmap_index_t bit_idx; |
| 401 | mem_region_t* region; |
| 402 | if (mi_memid_is_arena(id,®ion,&bit_idx,&arena_memid)) { |
| 403 | // was a direct arena allocation, pass through |
| 404 | _mi_arena_free(p, size, alignment, align_offset, arena_memid, full_commit, tld->stats); |
| 405 | } |
| 406 | else { |
| 407 | // allocated in a region |
| 408 | mi_assert_internal(align_offset == 0); |
| 409 | mi_assert_internal(size <= MI_REGION_MAX_OBJ_SIZE); if (size > MI_REGION_MAX_OBJ_SIZE) return; |
| 410 | const size_t blocks = mi_region_block_count(size); |
| 411 | mi_assert_internal(blocks + bit_idx <= MI_BITMAP_FIELD_BITS); |
| 412 | mi_region_info_t info; |
| 413 | info.value = mi_atomic_load_acquire(®ion->info); |
| 414 | mi_assert_internal(info.value != 0); |
| 415 | void* blocks_start = mi_region_blocks_start(region, bit_idx); |
| 416 | mi_assert_internal(blocks_start == p); // not a pointer in our area? |
| 417 | mi_assert_internal(bit_idx + blocks <= MI_BITMAP_FIELD_BITS); |
| 418 | if (blocks_start != p || bit_idx + blocks > MI_BITMAP_FIELD_BITS) return; // or `abort`? |
| 419 | |
| 420 | // committed? |
| 421 | if (full_commit && (size % MI_SEGMENT_SIZE) == 0) { |
| 422 | _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL); |
| 423 | } |
| 424 | |
| 425 | if (any_reset) { |
| 426 | // set the is_reset bits if any pages were reset |
| 427 | _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL); |
| 428 | } |
| 429 | |
| 430 | // reset the blocks to reduce the working set. |
| 431 | if (!info.x.is_large && !info.x.is_pinned && mi_option_is_enabled(mi_option_segment_reset) |
| 432 | && (mi_option_is_enabled(mi_option_eager_commit) || |
| 433 | mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead |
| 434 | { |
| 435 | bool any_unreset; |
| 436 | _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset); |
| 437 | if (any_unreset) { |
| 438 | _mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit) |
| 439 | _mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | // and unclaim |
| 444 | bool all_unclaimed = mi_bitmap_unclaim(®ion->in_use, 1, blocks, bit_idx); |
| 445 | mi_assert_internal(all_unclaimed); MI_UNUSED(all_unclaimed); |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | |
| 450 | /* ---------------------------------------------------------------------------- |
nothing calls this directly
no test coverage detected