1 #define JEMALLOC_ARENA_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
4 /******************************************************************************/
7 ssize_t opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT;
8 arena_bin_info_t arena_bin_info[NBINS];
10 JEMALLOC_ALIGNED(CACHELINE)
11 const uint8_t small_size2bin[] = {
13 #define S2B_16(i) S2B_8(i) S2B_8(i)
14 #define S2B_32(i) S2B_16(i) S2B_16(i)
15 #define S2B_64(i) S2B_32(i) S2B_32(i)
16 #define S2B_128(i) S2B_64(i) S2B_64(i)
17 #define S2B_256(i) S2B_128(i) S2B_128(i)
18 #define S2B_512(i) S2B_256(i) S2B_256(i)
19 #define S2B_1024(i) S2B_512(i) S2B_512(i)
20 #define S2B_2048(i) S2B_1024(i) S2B_1024(i)
21 #define S2B_4096(i) S2B_2048(i) S2B_2048(i)
22 #define S2B_8192(i) S2B_4096(i) S2B_4096(i)
23 #define SIZE_CLASS(bin, delta, size) \
40 /******************************************************************************/
42 * Function prototypes for static functions that are referenced prior to
46 static void arena_purge(arena_t *arena, bool all);
47 static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty,
49 static void arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk,
50 arena_run_t *run, arena_bin_t *bin);
51 static void arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk,
52 arena_run_t *run, arena_bin_t *bin);
54 /******************************************************************************/
57 arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
59 uintptr_t a_mapelm = (uintptr_t)a;
60 uintptr_t b_mapelm = (uintptr_t)b;
65 return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
68 /* Generate red-black tree functions. */
69 rb_gen(static UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
70 u.rb_link, arena_run_comp)
73 arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
76 size_t a_size = a->bits & ~PAGE_MASK;
77 size_t b_size = b->bits & ~PAGE_MASK;
79 ret = (a_size > b_size) - (a_size < b_size);
81 uintptr_t a_mapelm, b_mapelm;
83 if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY)
84 a_mapelm = (uintptr_t)a;
87 * Treat keys as though they are lower than anything
92 b_mapelm = (uintptr_t)b;
94 ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
100 /* Generate red-black tree functions. */
101 rb_gen(static UNUSED, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t,
102 u.rb_link, arena_avail_comp)
105 arena_chunk_dirty_comp(arena_chunk_t *a, arena_chunk_t *b)
112 * Short-circuit for self comparison. The following comparison code
113 * would come to the same result, but at the cost of executing the slow
120 * Order such that chunks with higher fragmentation are "less than"
121 * those with lower fragmentation -- purging order is from "least" to
122 * "greatest". Fragmentation is measured as:
124 * mean current avail run size
125 * --------------------------------
126 * mean defragmented avail run size
130 * nruns_avail nruns_avail-nruns_adjac
131 * = ========================= = -----------------------
133 * -----------------------
134 * nruns_avail-nruns_adjac
136 * The following code multiplies away the denominator prior to
137 * comparison, in order to avoid division.
141 size_t a_val = (a->nruns_avail - a->nruns_adjac) *
143 size_t b_val = (b->nruns_avail - b->nruns_adjac) *
152 * Break ties by chunk address. For fragmented chunks, report lower
153 * addresses as "lower", so that fragmentation reduction happens first
154 * at lower addresses. However, use the opposite ordering for
155 * unfragmented chunks, in order to increase the chances of
156 * re-allocating dirty runs.
159 uintptr_t a_chunk = (uintptr_t)a;
160 uintptr_t b_chunk = (uintptr_t)b;
161 int ret = ((a_chunk > b_chunk) - (a_chunk < b_chunk));
162 if (a->nruns_adjac == 0) {
163 assert(b->nruns_adjac == 0);
170 /* Generate red-black tree functions. */
171 rb_gen(static UNUSED, arena_chunk_dirty_, arena_chunk_tree_t, arena_chunk_t,
172 dirty_link, arena_chunk_dirty_comp)
175 arena_avail_adjac_pred(arena_chunk_t *chunk, size_t pageind)
179 if (pageind-1 < map_bias)
182 ret = (arena_mapbits_allocated_get(chunk, pageind-1) == 0);
183 assert(ret == false || arena_mapbits_dirty_get(chunk,
184 pageind-1) != arena_mapbits_dirty_get(chunk, pageind));
190 arena_avail_adjac_succ(arena_chunk_t *chunk, size_t pageind, size_t npages)
194 if (pageind+npages == chunk_npages)
197 assert(pageind+npages < chunk_npages);
198 ret = (arena_mapbits_allocated_get(chunk, pageind+npages) == 0);
199 assert(ret == false || arena_mapbits_dirty_get(chunk, pageind)
200 != arena_mapbits_dirty_get(chunk, pageind+npages));
206 arena_avail_adjac(arena_chunk_t *chunk, size_t pageind, size_t npages)
209 return (arena_avail_adjac_pred(chunk, pageind) ||
210 arena_avail_adjac_succ(chunk, pageind, npages));
214 arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind,
215 size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ)
218 assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >>
222 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
223 * removed and reinserted even if the run to be inserted is clean.
225 if (chunk->ndirty != 0)
226 arena_chunk_dirty_remove(&arena->chunks_dirty, chunk);
228 if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind))
229 chunk->nruns_adjac++;
230 if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages))
231 chunk->nruns_adjac++;
232 chunk->nruns_avail++;
233 assert(chunk->nruns_avail > chunk->nruns_adjac);
235 if (arena_mapbits_dirty_get(chunk, pageind) != 0) {
236 arena->ndirty += npages;
237 chunk->ndirty += npages;
239 if (chunk->ndirty != 0)
240 arena_chunk_dirty_insert(&arena->chunks_dirty, chunk);
242 arena_avail_tree_insert(&arena->runs_avail, arena_mapp_get(chunk,
247 arena_avail_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind,
248 size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ)
251 assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >>
255 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
256 * removed and reinserted even if the run to be removed is clean.
258 if (chunk->ndirty != 0)
259 arena_chunk_dirty_remove(&arena->chunks_dirty, chunk);
261 if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind))
262 chunk->nruns_adjac--;
263 if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages))
264 chunk->nruns_adjac--;
265 chunk->nruns_avail--;
266 assert(chunk->nruns_avail > chunk->nruns_adjac || (chunk->nruns_avail
267 == 0 && chunk->nruns_adjac == 0));
269 if (arena_mapbits_dirty_get(chunk, pageind) != 0) {
270 arena->ndirty -= npages;
271 chunk->ndirty -= npages;
273 if (chunk->ndirty != 0)
274 arena_chunk_dirty_insert(&arena->chunks_dirty, chunk);
276 arena_avail_tree_remove(&arena->runs_avail, arena_mapp_get(chunk,
281 arena_run_reg_alloc(arena_run_t *run, arena_bin_info_t *bin_info)
285 bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
286 (uintptr_t)bin_info->bitmap_offset);
288 assert(run->nfree > 0);
289 assert(bitmap_full(bitmap, &bin_info->bitmap_info) == false);
291 regind = bitmap_sfu(bitmap, &bin_info->bitmap_info);
292 ret = (void *)((uintptr_t)run + (uintptr_t)bin_info->reg0_offset +
293 (uintptr_t)(bin_info->reg_interval * regind));
295 if (regind == run->nextind)
297 assert(regind < run->nextind);
302 arena_run_reg_dalloc(arena_run_t *run, void *ptr)
304 arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
305 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
306 size_t mapbits = arena_mapbits_get(chunk, pageind);
307 size_t binind = arena_ptr_small_binind_get(ptr, mapbits);
308 arena_bin_info_t *bin_info = &arena_bin_info[binind];
309 unsigned regind = arena_run_regind(run, bin_info, ptr);
310 bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
311 (uintptr_t)bin_info->bitmap_offset);
313 assert(run->nfree < bin_info->nregs);
314 /* Freeing an interior pointer can cause assertion failure. */
315 assert(((uintptr_t)ptr - ((uintptr_t)run +
316 (uintptr_t)bin_info->reg0_offset)) %
317 (uintptr_t)bin_info->reg_interval == 0);
318 assert((uintptr_t)ptr >= (uintptr_t)run +
319 (uintptr_t)bin_info->reg0_offset);
320 /* Freeing an unallocated pointer can cause assertion failure. */
321 assert(bitmap_get(bitmap, &bin_info->bitmap_info, regind));
323 bitmap_unset(bitmap, &bin_info->bitmap_info, regind);
328 arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages)
331 VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind <<
332 LG_PAGE)), (npages << LG_PAGE));
333 memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0,
334 (npages << LG_PAGE));
338 arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind)
341 VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind <<
346 arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind)
349 UNUSED size_t *p = (size_t *)((uintptr_t)chunk + (run_ind << LG_PAGE));
351 arena_run_page_mark_zeroed(chunk, run_ind);
352 for (i = 0; i < PAGE / sizeof(size_t); i++)
357 arena_cactive_update(arena_t *arena, size_t add_pages, size_t sub_pages)
361 ssize_t cactive_diff = CHUNK_CEILING((arena->nactive +
362 add_pages) << LG_PAGE) - CHUNK_CEILING((arena->nactive -
363 sub_pages) << LG_PAGE);
364 if (cactive_diff != 0)
365 stats_cactive_add(cactive_diff);
370 arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind,
371 size_t flag_dirty, size_t need_pages)
373 size_t total_pages, rem_pages;
375 total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >>
377 assert(arena_mapbits_dirty_get(chunk, run_ind+total_pages-1) ==
379 assert(need_pages <= total_pages);
380 rem_pages = total_pages - need_pages;
382 arena_avail_remove(arena, chunk, run_ind, total_pages, true, true);
383 arena_cactive_update(arena, need_pages, 0);
384 arena->nactive += need_pages;
386 /* Keep track of trailing unused pages for later use. */
388 if (flag_dirty != 0) {
389 arena_mapbits_unallocated_set(chunk,
390 run_ind+need_pages, (rem_pages << LG_PAGE),
392 arena_mapbits_unallocated_set(chunk,
393 run_ind+total_pages-1, (rem_pages << LG_PAGE),
396 arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
397 (rem_pages << LG_PAGE),
398 arena_mapbits_unzeroed_get(chunk,
399 run_ind+need_pages));
400 arena_mapbits_unallocated_set(chunk,
401 run_ind+total_pages-1, (rem_pages << LG_PAGE),
402 arena_mapbits_unzeroed_get(chunk,
403 run_ind+total_pages-1));
405 arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages,
411 arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size,
412 bool remove, bool zero)
414 arena_chunk_t *chunk;
415 size_t flag_dirty, run_ind, need_pages, i;
417 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
418 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
419 flag_dirty = arena_mapbits_dirty_get(chunk, run_ind);
420 need_pages = (size >> LG_PAGE);
421 assert(need_pages > 0);
424 arena_run_split_remove(arena, chunk, run_ind, flag_dirty,
429 if (flag_dirty == 0) {
431 * The run is clean, so some pages may be zeroed (i.e.
432 * never before touched).
434 for (i = 0; i < need_pages; i++) {
435 if (arena_mapbits_unzeroed_get(chunk, run_ind+i)
437 arena_run_zero(chunk, run_ind+i, 1);
438 else if (config_debug) {
439 arena_run_page_validate_zeroed(chunk,
442 arena_run_page_mark_zeroed(chunk,
447 /* The run is dirty, so all pages must be zeroed. */
448 arena_run_zero(chunk, run_ind, need_pages);
451 VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
452 (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
456 * Set the last element first, in case the run only contains one page
457 * (i.e. both statements set the same element).
459 arena_mapbits_large_set(chunk, run_ind+need_pages-1, 0, flag_dirty);
460 arena_mapbits_large_set(chunk, run_ind, size, flag_dirty);
464 arena_run_split_large(arena_t *arena, arena_run_t *run, size_t size, bool zero)
467 arena_run_split_large_helper(arena, run, size, true, zero);
471 arena_run_init_large(arena_t *arena, arena_run_t *run, size_t size, bool zero)
474 arena_run_split_large_helper(arena, run, size, false, zero);
478 arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size,
481 arena_chunk_t *chunk;
482 size_t flag_dirty, run_ind, need_pages, i;
484 assert(binind != BININD_INVALID);
486 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
487 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
488 flag_dirty = arena_mapbits_dirty_get(chunk, run_ind);
489 need_pages = (size >> LG_PAGE);
490 assert(need_pages > 0);
492 arena_run_split_remove(arena, chunk, run_ind, flag_dirty, need_pages);
495 * Propagate the dirty and unzeroed flags to the allocated small run,
496 * so that arena_dalloc_bin_run() has the ability to conditionally trim
499 arena_mapbits_small_set(chunk, run_ind, 0, binind, flag_dirty);
501 * The first page will always be dirtied during small run
502 * initialization, so a validation failure here would not actually
503 * cause an observable failure.
505 if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk,
507 arena_run_page_validate_zeroed(chunk, run_ind);
508 for (i = 1; i < need_pages - 1; i++) {
509 arena_mapbits_small_set(chunk, run_ind+i, i, binind, 0);
510 if (config_debug && flag_dirty == 0 &&
511 arena_mapbits_unzeroed_get(chunk, run_ind+i) == 0)
512 arena_run_page_validate_zeroed(chunk, run_ind+i);
514 arena_mapbits_small_set(chunk, run_ind+need_pages-1, need_pages-1,
516 if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk,
517 run_ind+need_pages-1) == 0)
518 arena_run_page_validate_zeroed(chunk, run_ind+need_pages-1);
519 VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
520 (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
523 static arena_chunk_t *
524 arena_chunk_init_spare(arena_t *arena)
526 arena_chunk_t *chunk;
528 assert(arena->spare != NULL);
530 chunk = arena->spare;
533 assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
534 assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
535 assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
537 assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) ==
539 assert(arena_mapbits_dirty_get(chunk, map_bias) ==
540 arena_mapbits_dirty_get(chunk, chunk_npages-1));
545 static arena_chunk_t *
546 arena_chunk_init_hard(arena_t *arena)
548 arena_chunk_t *chunk;
552 assert(arena->spare == NULL);
555 malloc_mutex_unlock(&arena->lock);
556 chunk = (arena_chunk_t *)chunk_alloc(chunksize, chunksize, false,
557 &zero, arena->dss_prec);
558 malloc_mutex_lock(&arena->lock);
562 arena->stats.mapped += chunksize;
564 chunk->arena = arena;
567 * Claim that no pages are in use, since the header is merely overhead.
571 chunk->nruns_avail = 0;
572 chunk->nruns_adjac = 0;
575 * Initialize the map to contain one maximal free untouched run. Mark
576 * the pages as zeroed iff chunk_alloc() returned a zeroed chunk.
578 unzeroed = zero ? 0 : CHUNK_MAP_UNZEROED;
579 arena_mapbits_unallocated_set(chunk, map_bias, arena_maxclass,
582 * There is no need to initialize the internal page map entries unless
583 * the chunk is not zeroed.
586 VALGRIND_MAKE_MEM_UNDEFINED((void *)arena_mapp_get(chunk,
587 map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk,
588 chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
590 for (i = map_bias+1; i < chunk_npages-1; i++)
591 arena_mapbits_unzeroed_set(chunk, i, unzeroed);
593 VALGRIND_MAKE_MEM_DEFINED((void *)arena_mapp_get(chunk,
594 map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk,
595 chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
598 for (i = map_bias+1; i < chunk_npages-1; i++) {
599 assert(arena_mapbits_unzeroed_get(chunk, i) ==
604 arena_mapbits_unallocated_set(chunk, chunk_npages-1, arena_maxclass,
610 static arena_chunk_t *
611 arena_chunk_alloc(arena_t *arena)
613 arena_chunk_t *chunk;
615 if (arena->spare != NULL)
616 chunk = arena_chunk_init_spare(arena);
618 chunk = arena_chunk_init_hard(arena);
623 /* Insert the run into the runs_avail tree. */
624 arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias,
631 arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
633 assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
634 assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
635 assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
637 assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) ==
639 assert(arena_mapbits_dirty_get(chunk, map_bias) ==
640 arena_mapbits_dirty_get(chunk, chunk_npages-1));
643 * Remove run from the runs_avail tree, so that the arena does not use
646 arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias,
649 if (arena->spare != NULL) {
650 arena_chunk_t *spare = arena->spare;
652 arena->spare = chunk;
653 malloc_mutex_unlock(&arena->lock);
654 chunk_dealloc((void *)spare, chunksize, true);
655 malloc_mutex_lock(&arena->lock);
657 arena->stats.mapped -= chunksize;
659 arena->spare = chunk;
663 arena_run_alloc_large_helper(arena_t *arena, size_t size, bool zero)
666 arena_chunk_map_t *mapelm, key;
668 key.bits = size | CHUNK_MAP_KEY;
669 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
670 if (mapelm != NULL) {
671 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
672 size_t pageind = (((uintptr_t)mapelm -
673 (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t))
676 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind <<
678 arena_run_split_large(arena, run, size, zero);
686 arena_run_alloc_large(arena_t *arena, size_t size, bool zero)
688 arena_chunk_t *chunk;
691 assert(size <= arena_maxclass);
692 assert((size & PAGE_MASK) == 0);
694 /* Search the arena's chunks for the lowest best fit. */
695 run = arena_run_alloc_large_helper(arena, size, zero);
700 * No usable runs. Create a new chunk from which to allocate the run.
702 chunk = arena_chunk_alloc(arena);
704 run = (arena_run_t *)((uintptr_t)chunk + (map_bias << LG_PAGE));
705 arena_run_split_large(arena, run, size, zero);
710 * arena_chunk_alloc() failed, but another thread may have made
711 * sufficient memory available while this one dropped arena->lock in
712 * arena_chunk_alloc(), so search one more time.
714 return (arena_run_alloc_large_helper(arena, size, zero));
718 arena_run_alloc_small_helper(arena_t *arena, size_t size, size_t binind)
721 arena_chunk_map_t *mapelm, key;
723 key.bits = size | CHUNK_MAP_KEY;
724 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
725 if (mapelm != NULL) {
726 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
727 size_t pageind = (((uintptr_t)mapelm -
728 (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t))
731 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind <<
733 arena_run_split_small(arena, run, size, binind);
741 arena_run_alloc_small(arena_t *arena, size_t size, size_t binind)
743 arena_chunk_t *chunk;
746 assert(size <= arena_maxclass);
747 assert((size & PAGE_MASK) == 0);
748 assert(binind != BININD_INVALID);
750 /* Search the arena's chunks for the lowest best fit. */
751 run = arena_run_alloc_small_helper(arena, size, binind);
756 * No usable runs. Create a new chunk from which to allocate the run.
758 chunk = arena_chunk_alloc(arena);
760 run = (arena_run_t *)((uintptr_t)chunk + (map_bias << LG_PAGE));
761 arena_run_split_small(arena, run, size, binind);
766 * arena_chunk_alloc() failed, but another thread may have made
767 * sufficient memory available while this one dropped arena->lock in
768 * arena_chunk_alloc(), so search one more time.
770 return (arena_run_alloc_small_helper(arena, size, binind));
774 arena_maybe_purge(arena_t *arena)
776 size_t npurgeable, threshold;
778 /* Don't purge if the option is disabled. */
779 if (opt_lg_dirty_mult < 0)
781 /* Don't purge if all dirty pages are already being purged. */
782 if (arena->ndirty <= arena->npurgatory)
784 npurgeable = arena->ndirty - arena->npurgatory;
785 threshold = (arena->nactive >> opt_lg_dirty_mult);
787 * Don't purge unless the number of purgeable pages exceeds the
790 if (npurgeable <= threshold)
793 arena_purge(arena, false);
796 static arena_chunk_t *
797 chunks_dirty_iter_cb(arena_chunk_tree_t *tree, arena_chunk_t *chunk, void *arg)
799 size_t *ndirty = (size_t *)arg;
801 assert(chunk->ndirty != 0);
802 *ndirty += chunk->ndirty;
807 arena_compute_npurgatory(arena_t *arena, bool all)
809 size_t npurgatory, npurgeable;
812 * Compute the minimum number of pages that this thread should try to
815 npurgeable = arena->ndirty - arena->npurgatory;
818 size_t threshold = (arena->nactive >> opt_lg_dirty_mult);
820 npurgatory = npurgeable - threshold;
822 npurgatory = npurgeable;
828 arena_chunk_stash_dirty(arena_t *arena, arena_chunk_t *chunk, bool all,
829 arena_chunk_mapelms_t *mapelms)
831 size_t pageind, npages;
834 * Temporarily allocate free dirty runs within chunk. If all is false,
835 * only operate on dirty runs that are fragments; otherwise operate on
838 for (pageind = map_bias; pageind < chunk_npages; pageind += npages) {
839 arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind);
840 if (arena_mapbits_allocated_get(chunk, pageind) == 0) {
842 arena_mapbits_unallocated_size_get(chunk, pageind);
844 npages = run_size >> LG_PAGE;
845 assert(pageind + npages <= chunk_npages);
846 assert(arena_mapbits_dirty_get(chunk, pageind) ==
847 arena_mapbits_dirty_get(chunk, pageind+npages-1));
849 if (arena_mapbits_dirty_get(chunk, pageind) != 0 &&
850 (all || arena_avail_adjac(chunk, pageind,
852 arena_run_t *run = (arena_run_t *)((uintptr_t)
853 chunk + (uintptr_t)(pageind << LG_PAGE));
855 arena_run_split_large(arena, run, run_size,
857 /* Append to list for later processing. */
858 ql_elm_new(mapelm, u.ql_link);
859 ql_tail_insert(mapelms, mapelm, u.ql_link);
863 if (arena_mapbits_large_get(chunk, pageind) != 0) {
864 npages = arena_mapbits_large_size_get(chunk,
868 arena_bin_info_t *bin_info;
869 arena_run_t *run = (arena_run_t *)((uintptr_t)
870 chunk + (uintptr_t)(pageind << LG_PAGE));
872 assert(arena_mapbits_small_runind_get(chunk,
874 binind = arena_bin_index(arena, run->bin);
875 bin_info = &arena_bin_info[binind];
876 npages = bin_info->run_size >> LG_PAGE;
880 assert(pageind == chunk_npages);
881 assert(chunk->ndirty == 0 || all == false);
882 assert(chunk->nruns_adjac == 0);
886 arena_chunk_purge_stashed(arena_t *arena, arena_chunk_t *chunk,
887 arena_chunk_mapelms_t *mapelms)
889 size_t npurged, pageind, npages, nmadvise;
890 arena_chunk_map_t *mapelm;
892 malloc_mutex_unlock(&arena->lock);
896 ql_foreach(mapelm, mapelms, u.ql_link) {
898 size_t flag_unzeroed, i;
900 pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
901 sizeof(arena_chunk_map_t)) + map_bias;
902 npages = arena_mapbits_large_size_get(chunk, pageind) >>
904 assert(pageind + npages <= chunk_npages);
905 unzeroed = pages_purge((void *)((uintptr_t)chunk + (pageind <<
906 LG_PAGE)), (npages << LG_PAGE));
907 flag_unzeroed = unzeroed ? CHUNK_MAP_UNZEROED : 0;
909 * Set the unzeroed flag for all pages, now that pages_purge()
910 * has returned whether the pages were zeroed as a side effect
911 * of purging. This chunk map modification is safe even though
912 * the arena mutex isn't currently owned by this thread,
913 * because the run is marked as allocated, thus protecting it
914 * from being modified by any other thread. As long as these
915 * writes don't perturb the first and last elements'
916 * CHUNK_MAP_ALLOCATED bits, behavior is well defined.
918 for (i = 0; i < npages; i++) {
919 arena_mapbits_unzeroed_set(chunk, pageind+i,
926 malloc_mutex_lock(&arena->lock);
928 arena->stats.nmadvise += nmadvise;
934 arena_chunk_unstash_purged(arena_t *arena, arena_chunk_t *chunk,
935 arena_chunk_mapelms_t *mapelms)
937 arena_chunk_map_t *mapelm;
940 /* Deallocate runs. */
941 for (mapelm = ql_first(mapelms); mapelm != NULL;
942 mapelm = ql_first(mapelms)) {
945 pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
946 sizeof(arena_chunk_map_t)) + map_bias;
947 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)(pageind <<
949 ql_remove(mapelms, mapelm, u.ql_link);
950 arena_run_dalloc(arena, run, false, true);
955 arena_chunk_purge(arena_t *arena, arena_chunk_t *chunk, bool all)
958 arena_chunk_mapelms_t mapelms;
963 * If chunk is the spare, temporarily re-allocate it, 1) so that its
964 * run is reinserted into runs_avail, and 2) so that it cannot be
965 * completely discarded by another thread while arena->lock is dropped
966 * by this thread. Note that the arena_run_dalloc() call will
967 * implicitly deallocate the chunk, so no explicit action is required
968 * in this function to deallocate the chunk.
970 * Note that once a chunk contains dirty pages, it cannot again contain
971 * a single run unless 1) it is a dirty run, or 2) this function purges
972 * dirty pages and causes the transition to a single clean run. Thus
973 * (chunk == arena->spare) is possible, but it is not possible for
974 * this function to be called on the spare unless it contains a dirty
977 if (chunk == arena->spare) {
978 assert(arena_mapbits_dirty_get(chunk, map_bias) != 0);
979 assert(arena_mapbits_dirty_get(chunk, chunk_npages-1) != 0);
981 arena_chunk_alloc(arena);
985 arena->stats.purged += chunk->ndirty;
988 * Operate on all dirty runs if there is no clean/dirty run
991 if (chunk->nruns_adjac == 0)
994 arena_chunk_stash_dirty(arena, chunk, all, &mapelms);
995 npurged = arena_chunk_purge_stashed(arena, chunk, &mapelms);
996 arena_chunk_unstash_purged(arena, chunk, &mapelms);
1002 arena_purge(arena_t *arena, bool all)
1004 arena_chunk_t *chunk;
1009 arena_chunk_dirty_iter(&arena->chunks_dirty, NULL,
1010 chunks_dirty_iter_cb, (void *)&ndirty);
1011 assert(ndirty == arena->ndirty);
1013 assert(arena->ndirty > arena->npurgatory || all);
1014 assert((arena->nactive >> opt_lg_dirty_mult) < (arena->ndirty -
1015 arena->npurgatory) || all);
1018 arena->stats.npurge++;
1021 * Add the minimum number of pages this thread should try to purge to
1022 * arena->npurgatory. This will keep multiple threads from racing to
1023 * reduce ndirty below the threshold.
1025 npurgatory = arena_compute_npurgatory(arena, all);
1026 arena->npurgatory += npurgatory;
1028 while (npurgatory > 0) {
1029 size_t npurgeable, npurged, nunpurged;
1031 /* Get next chunk with dirty pages. */
1032 chunk = arena_chunk_dirty_first(&arena->chunks_dirty);
1033 if (chunk == NULL) {
1035 * This thread was unable to purge as many pages as
1036 * originally intended, due to races with other threads
1037 * that either did some of the purging work, or re-used
1040 arena->npurgatory -= npurgatory;
1043 npurgeable = chunk->ndirty;
1044 assert(npurgeable != 0);
1046 if (npurgeable > npurgatory && chunk->nruns_adjac == 0) {
1048 * This thread will purge all the dirty pages in chunk,
1049 * so set npurgatory to reflect this thread's intent to
1050 * purge the pages. This tends to reduce the chances
1051 * of the following scenario:
1053 * 1) This thread sets arena->npurgatory such that
1054 * (arena->ndirty - arena->npurgatory) is at the
1056 * 2) This thread drops arena->lock.
1057 * 3) Another thread causes one or more pages to be
1058 * dirtied, and immediately determines that it must
1059 * purge dirty pages.
1061 * If this scenario *does* play out, that's okay,
1062 * because all of the purging work being done really
1065 arena->npurgatory += npurgeable - npurgatory;
1066 npurgatory = npurgeable;
1070 * Keep track of how many pages are purgeable, versus how many
1071 * actually get purged, and adjust counters accordingly.
1073 arena->npurgatory -= npurgeable;
1074 npurgatory -= npurgeable;
1075 npurged = arena_chunk_purge(arena, chunk, all);
1076 nunpurged = npurgeable - npurged;
1077 arena->npurgatory += nunpurged;
1078 npurgatory += nunpurged;
1083 arena_purge_all(arena_t *arena)
1086 malloc_mutex_lock(&arena->lock);
1087 arena_purge(arena, true);
1088 malloc_mutex_unlock(&arena->lock);
1092 arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size,
1093 size_t *p_run_ind, size_t *p_run_pages, size_t flag_dirty)
1095 size_t size = *p_size;
1096 size_t run_ind = *p_run_ind;
1097 size_t run_pages = *p_run_pages;
1099 /* Try to coalesce forward. */
1100 if (run_ind + run_pages < chunk_npages &&
1101 arena_mapbits_allocated_get(chunk, run_ind+run_pages) == 0 &&
1102 arena_mapbits_dirty_get(chunk, run_ind+run_pages) == flag_dirty) {
1103 size_t nrun_size = arena_mapbits_unallocated_size_get(chunk,
1105 size_t nrun_pages = nrun_size >> LG_PAGE;
1108 * Remove successor from runs_avail; the coalesced run is
1111 assert(arena_mapbits_unallocated_size_get(chunk,
1112 run_ind+run_pages+nrun_pages-1) == nrun_size);
1113 assert(arena_mapbits_dirty_get(chunk,
1114 run_ind+run_pages+nrun_pages-1) == flag_dirty);
1115 arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages,
1119 run_pages += nrun_pages;
1121 arena_mapbits_unallocated_size_set(chunk, run_ind, size);
1122 arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1,
1126 /* Try to coalesce backward. */
1127 if (run_ind > map_bias && arena_mapbits_allocated_get(chunk,
1128 run_ind-1) == 0 && arena_mapbits_dirty_get(chunk, run_ind-1) ==
1130 size_t prun_size = arena_mapbits_unallocated_size_get(chunk,
1132 size_t prun_pages = prun_size >> LG_PAGE;
1134 run_ind -= prun_pages;
1137 * Remove predecessor from runs_avail; the coalesced run is
1140 assert(arena_mapbits_unallocated_size_get(chunk, run_ind) ==
1142 assert(arena_mapbits_dirty_get(chunk, run_ind) == flag_dirty);
1143 arena_avail_remove(arena, chunk, run_ind, prun_pages, true,
1147 run_pages += prun_pages;
1149 arena_mapbits_unallocated_size_set(chunk, run_ind, size);
1150 arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1,
1155 *p_run_ind = run_ind;
1156 *p_run_pages = run_pages;
1160 arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
1162 arena_chunk_t *chunk;
1163 size_t size, run_ind, run_pages, flag_dirty;
1165 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1166 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
1167 assert(run_ind >= map_bias);
1168 assert(run_ind < chunk_npages);
1169 if (arena_mapbits_large_get(chunk, run_ind) != 0) {
1170 size = arena_mapbits_large_size_get(chunk, run_ind);
1171 assert(size == PAGE ||
1172 arena_mapbits_large_size_get(chunk,
1173 run_ind+(size>>LG_PAGE)-1) == 0);
1175 size_t binind = arena_bin_index(arena, run->bin);
1176 arena_bin_info_t *bin_info = &arena_bin_info[binind];
1177 size = bin_info->run_size;
1179 run_pages = (size >> LG_PAGE);
1180 arena_cactive_update(arena, 0, run_pages);
1181 arena->nactive -= run_pages;
1184 * The run is dirty if the caller claims to have dirtied it, as well as
1185 * if it was already dirty before being allocated and the caller
1186 * doesn't claim to have cleaned it.
1188 assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1189 arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
1190 if (cleaned == false && arena_mapbits_dirty_get(chunk, run_ind) != 0)
1192 flag_dirty = dirty ? CHUNK_MAP_DIRTY : 0;
1194 /* Mark pages as unallocated in the chunk map. */
1196 arena_mapbits_unallocated_set(chunk, run_ind, size,
1198 arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size,
1201 arena_mapbits_unallocated_set(chunk, run_ind, size,
1202 arena_mapbits_unzeroed_get(chunk, run_ind));
1203 arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size,
1204 arena_mapbits_unzeroed_get(chunk, run_ind+run_pages-1));
1207 arena_run_coalesce(arena, chunk, &size, &run_ind, &run_pages,
1210 /* Insert into runs_avail, now that coalescing is complete. */
1211 assert(arena_mapbits_unallocated_size_get(chunk, run_ind) ==
1212 arena_mapbits_unallocated_size_get(chunk, run_ind+run_pages-1));
1213 assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1214 arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
1215 arena_avail_insert(arena, chunk, run_ind, run_pages, true, true);
1217 /* Deallocate chunk if it is now completely unused. */
1218 if (size == arena_maxclass) {
1219 assert(run_ind == map_bias);
1220 assert(run_pages == (arena_maxclass >> LG_PAGE));
1221 arena_chunk_dealloc(arena, chunk);
1225 * It is okay to do dirty page processing here even if the chunk was
1226 * deallocated above, since in that case it is the spare. Waiting
1227 * until after possible chunk deallocation to do dirty processing
1228 * allows for an old spare to be fully deallocated, thus decreasing the
1229 * chances of spuriously crossing the dirty page purging threshold.
1232 arena_maybe_purge(arena);
1236 arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1237 size_t oldsize, size_t newsize)
1239 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1240 size_t head_npages = (oldsize - newsize) >> LG_PAGE;
1241 size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind);
1243 assert(oldsize > newsize);
1246 * Update the chunk map so that arena_run_dalloc() can treat the
1247 * leading run as separately allocated. Set the last element of each
1248 * run first, in case of single-page runs.
1250 assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize);
1251 arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty);
1252 arena_mapbits_large_set(chunk, pageind, oldsize-newsize, flag_dirty);
1255 UNUSED size_t tail_npages = newsize >> LG_PAGE;
1256 assert(arena_mapbits_large_size_get(chunk,
1257 pageind+head_npages+tail_npages-1) == 0);
1258 assert(arena_mapbits_dirty_get(chunk,
1259 pageind+head_npages+tail_npages-1) == flag_dirty);
1261 arena_mapbits_large_set(chunk, pageind+head_npages, newsize,
1264 arena_run_dalloc(arena, run, false, false);
1268 arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1269 size_t oldsize, size_t newsize, bool dirty)
1271 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1272 size_t head_npages = newsize >> LG_PAGE;
1273 size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind);
1275 assert(oldsize > newsize);
1278 * Update the chunk map so that arena_run_dalloc() can treat the
1279 * trailing run as separately allocated. Set the last element of each
1280 * run first, in case of single-page runs.
1282 assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize);
1283 arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty);
1284 arena_mapbits_large_set(chunk, pageind, newsize, flag_dirty);
1287 UNUSED size_t tail_npages = (oldsize - newsize) >> LG_PAGE;
1288 assert(arena_mapbits_large_size_get(chunk,
1289 pageind+head_npages+tail_npages-1) == 0);
1290 assert(arena_mapbits_dirty_get(chunk,
1291 pageind+head_npages+tail_npages-1) == flag_dirty);
1293 arena_mapbits_large_set(chunk, pageind+head_npages, oldsize-newsize,
1296 arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
1300 static arena_run_t *
1301 arena_bin_runs_first(arena_bin_t *bin)
1303 arena_chunk_map_t *mapelm = arena_run_tree_first(&bin->runs);
1304 if (mapelm != NULL) {
1305 arena_chunk_t *chunk;
1309 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm);
1310 pageind = ((((uintptr_t)mapelm - (uintptr_t)chunk->map) /
1311 sizeof(arena_chunk_map_t))) + map_bias;
1312 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1313 arena_mapbits_small_runind_get(chunk, pageind)) <<
1322 arena_bin_runs_insert(arena_bin_t *bin, arena_run_t *run)
1324 arena_chunk_t *chunk = CHUNK_ADDR2BASE(run);
1325 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1326 arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind);
1328 assert(arena_run_tree_search(&bin->runs, mapelm) == NULL);
1330 arena_run_tree_insert(&bin->runs, mapelm);
1334 arena_bin_runs_remove(arena_bin_t *bin, arena_run_t *run)
1336 arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1337 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1338 arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind);
1340 assert(arena_run_tree_search(&bin->runs, mapelm) != NULL);
1342 arena_run_tree_remove(&bin->runs, mapelm);
1345 static arena_run_t *
1346 arena_bin_nonfull_run_tryget(arena_bin_t *bin)
1348 arena_run_t *run = arena_bin_runs_first(bin);
1350 arena_bin_runs_remove(bin, run);
1352 bin->stats.reruns++;
1357 static arena_run_t *
1358 arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
1362 arena_bin_info_t *bin_info;
1364 /* Look for a usable run. */
1365 run = arena_bin_nonfull_run_tryget(bin);
1368 /* No existing runs have any space available. */
1370 binind = arena_bin_index(arena, bin);
1371 bin_info = &arena_bin_info[binind];
1373 /* Allocate a new run. */
1374 malloc_mutex_unlock(&bin->lock);
1375 /******************************/
1376 malloc_mutex_lock(&arena->lock);
1377 run = arena_run_alloc_small(arena, bin_info->run_size, binind);
1379 bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
1380 (uintptr_t)bin_info->bitmap_offset);
1382 /* Initialize run internals. */
1385 run->nfree = bin_info->nregs;
1386 bitmap_init(bitmap, &bin_info->bitmap_info);
1388 malloc_mutex_unlock(&arena->lock);
1389 /********************************/
1390 malloc_mutex_lock(&bin->lock);
1394 bin->stats.curruns++;
1400 * arena_run_alloc_small() failed, but another thread may have made
1401 * sufficient memory available while this one dropped bin->lock above,
1402 * so search one more time.
1404 run = arena_bin_nonfull_run_tryget(bin);
1411 /* Re-fill bin->runcur, then call arena_run_reg_alloc(). */
1413 arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
1417 arena_bin_info_t *bin_info;
1420 binind = arena_bin_index(arena, bin);
1421 bin_info = &arena_bin_info[binind];
1423 run = arena_bin_nonfull_run_get(arena, bin);
1424 if (bin->runcur != NULL && bin->runcur->nfree > 0) {
1426 * Another thread updated runcur while this one ran without the
1427 * bin lock in arena_bin_nonfull_run_get().
1429 assert(bin->runcur->nfree > 0);
1430 ret = arena_run_reg_alloc(bin->runcur, bin_info);
1432 arena_chunk_t *chunk;
1435 * arena_run_alloc_small() may have allocated run, or
1436 * it may have pulled run from the bin's run tree.
1437 * Therefore it is unsafe to make any assumptions about
1438 * how run has previously been used, and
1439 * arena_bin_lower_run() must be called, as if a region
1440 * were just deallocated from the run.
1442 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1443 if (run->nfree == bin_info->nregs)
1444 arena_dalloc_bin_run(arena, chunk, run, bin);
1446 arena_bin_lower_run(arena, chunk, run, bin);
1456 assert(bin->runcur->nfree > 0);
1458 return (arena_run_reg_alloc(bin->runcur, bin_info));
1462 arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind,
1463 uint64_t prof_accumbytes)
1470 assert(tbin->ncached == 0);
1472 if (config_prof && arena_prof_accum(arena, prof_accumbytes))
1474 bin = &arena->bins[binind];
1475 malloc_mutex_lock(&bin->lock);
1476 for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >>
1477 tbin->lg_fill_div); i < nfill; i++) {
1478 if ((run = bin->runcur) != NULL && run->nfree > 0)
1479 ptr = arena_run_reg_alloc(run, &arena_bin_info[binind]);
1481 ptr = arena_bin_malloc_hard(arena, bin);
1484 if (config_fill && opt_junk) {
1485 arena_alloc_junk_small(ptr, &arena_bin_info[binind],
1488 /* Insert such that low regions get used first. */
1489 tbin->avail[nfill - 1 - i] = ptr;
1492 bin->stats.allocated += i * arena_bin_info[binind].reg_size;
1493 bin->stats.nmalloc += i;
1494 bin->stats.nrequests += tbin->tstats.nrequests;
1495 bin->stats.nfills++;
1496 tbin->tstats.nrequests = 0;
1498 malloc_mutex_unlock(&bin->lock);
1503 arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero)
1507 size_t redzone_size = bin_info->redzone_size;
1508 memset((void *)((uintptr_t)ptr - redzone_size), 0xa5,
1510 memset((void *)((uintptr_t)ptr + bin_info->reg_size), 0xa5,
1513 memset((void *)((uintptr_t)ptr - bin_info->redzone_size), 0xa5,
1514 bin_info->reg_interval);
1519 #undef arena_redzone_corruption
1520 #define arena_redzone_corruption JEMALLOC_N(arena_redzone_corruption_impl)
1523 arena_redzone_corruption(void *ptr, size_t usize, bool after,
1524 size_t offset, uint8_t byte)
1527 malloc_printf("<jemalloc>: Corrupt redzone %zu byte%s %s %p "
1528 "(size %zu), byte=%#x\n", offset, (offset == 1) ? "" : "s",
1529 after ? "after" : "before", ptr, usize, byte);
1532 #undef arena_redzone_corruption
1533 #define arena_redzone_corruption JEMALLOC_N(arena_redzone_corruption)
1534 arena_redzone_corruption_t *arena_redzone_corruption =
1535 JEMALLOC_N(arena_redzone_corruption_impl);
1539 arena_redzones_validate(void *ptr, arena_bin_info_t *bin_info, bool reset)
1541 size_t size = bin_info->reg_size;
1542 size_t redzone_size = bin_info->redzone_size;
1546 for (i = 1; i <= redzone_size; i++) {
1547 uint8_t *byte = (uint8_t *)((uintptr_t)ptr - i);
1548 if (*byte != 0xa5) {
1550 arena_redzone_corruption(ptr, size, false, i, *byte);
1555 for (i = 0; i < redzone_size; i++) {
1556 uint8_t *byte = (uint8_t *)((uintptr_t)ptr + size + i);
1557 if (*byte != 0xa5) {
1559 arena_redzone_corruption(ptr, size, true, i, *byte);
1564 if (opt_abort && error)
1569 #undef arena_dalloc_junk_small
1570 #define arena_dalloc_junk_small JEMALLOC_N(arena_dalloc_junk_small_impl)
1573 arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info)
1575 size_t redzone_size = bin_info->redzone_size;
1577 arena_redzones_validate(ptr, bin_info, false);
1578 memset((void *)((uintptr_t)ptr - redzone_size), 0x5a,
1579 bin_info->reg_interval);
1582 #undef arena_dalloc_junk_small
1583 #define arena_dalloc_junk_small JEMALLOC_N(arena_dalloc_junk_small)
1584 arena_dalloc_junk_small_t *arena_dalloc_junk_small =
1585 JEMALLOC_N(arena_dalloc_junk_small_impl);
1589 arena_quarantine_junk_small(void *ptr, size_t usize)
1592 arena_bin_info_t *bin_info;
1593 cassert(config_fill);
1595 assert(opt_quarantine);
1596 assert(usize <= SMALL_MAXCLASS);
1598 binind = SMALL_SIZE2BIN(usize);
1599 bin_info = &arena_bin_info[binind];
1600 arena_redzones_validate(ptr, bin_info, true);
1604 arena_malloc_small(arena_t *arena, size_t size, bool zero)
1611 binind = SMALL_SIZE2BIN(size);
1612 assert(binind < NBINS);
1613 bin = &arena->bins[binind];
1614 size = arena_bin_info[binind].reg_size;
1616 malloc_mutex_lock(&bin->lock);
1617 if ((run = bin->runcur) != NULL && run->nfree > 0)
1618 ret = arena_run_reg_alloc(run, &arena_bin_info[binind]);
1620 ret = arena_bin_malloc_hard(arena, bin);
1623 malloc_mutex_unlock(&bin->lock);
1628 bin->stats.allocated += size;
1629 bin->stats.nmalloc++;
1630 bin->stats.nrequests++;
1632 malloc_mutex_unlock(&bin->lock);
1633 if (config_prof && isthreaded == false && arena_prof_accum(arena, size))
1636 if (zero == false) {
1639 arena_alloc_junk_small(ret,
1640 &arena_bin_info[binind], false);
1641 } else if (opt_zero)
1642 memset(ret, 0, size);
1644 VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
1646 if (config_fill && opt_junk) {
1647 arena_alloc_junk_small(ret, &arena_bin_info[binind],
1650 VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
1651 memset(ret, 0, size);
1658 arena_malloc_large(arena_t *arena, size_t size, bool zero)
1663 /* Large allocation. */
1664 size = PAGE_CEILING(size);
1665 malloc_mutex_lock(&arena->lock);
1666 ret = (void *)arena_run_alloc_large(arena, size, zero);
1668 malloc_mutex_unlock(&arena->lock);
1672 arena->stats.nmalloc_large++;
1673 arena->stats.nrequests_large++;
1674 arena->stats.allocated_large += size;
1675 arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1676 arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1677 arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1680 idump = arena_prof_accum_locked(arena, size);
1681 malloc_mutex_unlock(&arena->lock);
1682 if (config_prof && idump)
1685 if (zero == false) {
1688 memset(ret, 0xa5, size);
1690 memset(ret, 0, size);
1697 /* Only handles large allocations that require more than page alignment. */
1699 arena_palloc(arena_t *arena, size_t size, size_t alignment, bool zero)
1702 size_t alloc_size, leadsize, trailsize;
1704 arena_chunk_t *chunk;
1706 assert((size & PAGE_MASK) == 0);
1708 alignment = PAGE_CEILING(alignment);
1709 alloc_size = size + alignment - PAGE;
1711 malloc_mutex_lock(&arena->lock);
1712 run = arena_run_alloc_large(arena, alloc_size, false);
1714 malloc_mutex_unlock(&arena->lock);
1717 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1719 leadsize = ALIGNMENT_CEILING((uintptr_t)run, alignment) -
1721 assert(alloc_size >= leadsize + size);
1722 trailsize = alloc_size - leadsize - size;
1723 ret = (void *)((uintptr_t)run + leadsize);
1724 if (leadsize != 0) {
1725 arena_run_trim_head(arena, chunk, run, alloc_size, alloc_size -
1728 if (trailsize != 0) {
1729 arena_run_trim_tail(arena, chunk, ret, size + trailsize, size,
1732 arena_run_init_large(arena, (arena_run_t *)ret, size, zero);
1735 arena->stats.nmalloc_large++;
1736 arena->stats.nrequests_large++;
1737 arena->stats.allocated_large += size;
1738 arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1739 arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1740 arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1742 malloc_mutex_unlock(&arena->lock);
1744 if (config_fill && zero == false) {
1746 memset(ret, 0xa5, size);
1748 memset(ret, 0, size);
1754 arena_prof_promoted(const void *ptr, size_t size)
1756 arena_chunk_t *chunk;
1757 size_t pageind, binind;
1759 cassert(config_prof);
1760 assert(ptr != NULL);
1761 assert(CHUNK_ADDR2BASE(ptr) != ptr);
1762 assert(isalloc(ptr, false) == PAGE);
1763 assert(isalloc(ptr, true) == PAGE);
1764 assert(size <= SMALL_MAXCLASS);
1766 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1767 pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1768 binind = SMALL_SIZE2BIN(size);
1769 assert(binind < NBINS);
1770 arena_mapbits_large_binind_set(chunk, pageind, binind);
1772 assert(isalloc(ptr, false) == PAGE);
1773 assert(isalloc(ptr, true) == size);
1777 arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run,
1781 /* Dissociate run from bin. */
1782 if (run == bin->runcur)
1785 size_t binind = arena_bin_index(chunk->arena, bin);
1786 arena_bin_info_t *bin_info = &arena_bin_info[binind];
1788 if (bin_info->nregs != 1) {
1790 * This block's conditional is necessary because if the
1791 * run only contains one region, then it never gets
1792 * inserted into the non-full runs tree.
1794 arena_bin_runs_remove(bin, run);
1800 arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1804 arena_bin_info_t *bin_info;
1805 size_t npages, run_ind, past;
1807 assert(run != bin->runcur);
1808 assert(arena_run_tree_search(&bin->runs,
1809 arena_mapp_get(chunk, ((uintptr_t)run-(uintptr_t)chunk)>>LG_PAGE))
1812 binind = arena_bin_index(chunk->arena, run->bin);
1813 bin_info = &arena_bin_info[binind];
1815 malloc_mutex_unlock(&bin->lock);
1816 /******************************/
1817 npages = bin_info->run_size >> LG_PAGE;
1818 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
1819 past = (size_t)(PAGE_CEILING((uintptr_t)run +
1820 (uintptr_t)bin_info->reg0_offset + (uintptr_t)(run->nextind *
1821 bin_info->reg_interval - bin_info->redzone_size) -
1822 (uintptr_t)chunk) >> LG_PAGE);
1823 malloc_mutex_lock(&arena->lock);
1826 * If the run was originally clean, and some pages were never touched,
1827 * trim the clean pages before deallocating the dirty portion of the
1830 assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1831 arena_mapbits_dirty_get(chunk, run_ind+npages-1));
1832 if (arena_mapbits_dirty_get(chunk, run_ind) == 0 && past - run_ind <
1834 /* Trim clean pages. Convert to large run beforehand. */
1836 arena_mapbits_large_set(chunk, run_ind, bin_info->run_size, 0);
1837 arena_mapbits_large_set(chunk, run_ind+npages-1, 0, 0);
1838 arena_run_trim_tail(arena, chunk, run, (npages << LG_PAGE),
1839 ((past - run_ind) << LG_PAGE), false);
1840 /* npages = past - run_ind; */
1842 arena_run_dalloc(arena, run, true, false);
1843 malloc_mutex_unlock(&arena->lock);
1844 /****************************/
1845 malloc_mutex_lock(&bin->lock);
1847 bin->stats.curruns--;
1851 arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1856 * Make sure that if bin->runcur is non-NULL, it refers to the lowest
1857 * non-full run. It is okay to NULL runcur out rather than proactively
1858 * keeping it pointing at the lowest non-full run.
1860 if ((uintptr_t)run < (uintptr_t)bin->runcur) {
1861 /* Switch runcur. */
1862 if (bin->runcur->nfree > 0)
1863 arena_bin_runs_insert(bin, bin->runcur);
1866 bin->stats.reruns++;
1868 arena_bin_runs_insert(bin, run);
1872 arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1873 arena_chunk_map_t *mapelm)
1878 arena_bin_info_t *bin_info;
1879 size_t size, binind;
1881 pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1882 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1883 arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE));
1885 binind = arena_ptr_small_binind_get(ptr, mapelm->bits);
1886 bin_info = &arena_bin_info[binind];
1887 if (config_fill || config_stats)
1888 size = bin_info->reg_size;
1890 if (config_fill && opt_junk)
1891 arena_dalloc_junk_small(ptr, bin_info);
1893 arena_run_reg_dalloc(run, ptr);
1894 if (run->nfree == bin_info->nregs) {
1895 arena_dissociate_bin_run(chunk, run, bin);
1896 arena_dalloc_bin_run(arena, chunk, run, bin);
1897 } else if (run->nfree == 1 && run != bin->runcur)
1898 arena_bin_lower_run(arena, chunk, run, bin);
1901 bin->stats.allocated -= size;
1902 bin->stats.ndalloc++;
1907 arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1908 size_t pageind, arena_chunk_map_t *mapelm)
1913 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1914 arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE));
1916 malloc_mutex_lock(&bin->lock);
1917 arena_dalloc_bin_locked(arena, chunk, ptr, mapelm);
1918 malloc_mutex_unlock(&bin->lock);
1922 arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1925 arena_chunk_map_t *mapelm;
1928 /* arena_ptr_small_binind_get() does extra sanity checking. */
1929 assert(arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk,
1930 pageind)) != BININD_INVALID);
1932 mapelm = arena_mapp_get(chunk, pageind);
1933 arena_dalloc_bin(arena, chunk, ptr, pageind, mapelm);
1937 #undef arena_dalloc_junk_large
1938 #define arena_dalloc_junk_large JEMALLOC_N(arena_dalloc_junk_large_impl)
1941 arena_dalloc_junk_large(void *ptr, size_t usize)
1944 if (config_fill && opt_junk)
1945 memset(ptr, 0x5a, usize);
1948 #undef arena_dalloc_junk_large
1949 #define arena_dalloc_junk_large JEMALLOC_N(arena_dalloc_junk_large)
1950 arena_dalloc_junk_large_t *arena_dalloc_junk_large =
1951 JEMALLOC_N(arena_dalloc_junk_large_impl);
1955 arena_dalloc_large_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr)
1958 if (config_fill || config_stats) {
1959 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1960 size_t usize = arena_mapbits_large_size_get(chunk, pageind);
1962 arena_dalloc_junk_large(ptr, usize);
1964 arena->stats.ndalloc_large++;
1965 arena->stats.allocated_large -= usize;
1966 arena->stats.lstats[(usize >> LG_PAGE) - 1].ndalloc++;
1967 arena->stats.lstats[(usize >> LG_PAGE) - 1].curruns--;
1971 arena_run_dalloc(arena, (arena_run_t *)ptr, true, false);
1975 arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
1978 malloc_mutex_lock(&arena->lock);
1979 arena_dalloc_large_locked(arena, chunk, ptr);
1980 malloc_mutex_unlock(&arena->lock);
1984 arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1985 size_t oldsize, size_t size)
1988 assert(size < oldsize);
1991 * Shrink the run, and make trailing pages available for other
1994 malloc_mutex_lock(&arena->lock);
1995 arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
1998 arena->stats.ndalloc_large++;
1999 arena->stats.allocated_large -= oldsize;
2000 arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++;
2001 arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--;
2003 arena->stats.nmalloc_large++;
2004 arena->stats.nrequests_large++;
2005 arena->stats.allocated_large += size;
2006 arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
2007 arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
2008 arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
2010 malloc_mutex_unlock(&arena->lock);
2014 arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
2015 size_t oldsize, size_t size, size_t extra, bool zero)
2017 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
2018 size_t npages = oldsize >> LG_PAGE;
2021 assert(oldsize == arena_mapbits_large_size_get(chunk, pageind));
2023 /* Try to extend the run. */
2024 assert(size + extra > oldsize);
2025 malloc_mutex_lock(&arena->lock);
2026 if (pageind + npages < chunk_npages &&
2027 arena_mapbits_allocated_get(chunk, pageind+npages) == 0 &&
2028 (followsize = arena_mapbits_unallocated_size_get(chunk,
2029 pageind+npages)) >= size - oldsize) {
2031 * The next run is available and sufficiently large. Split the
2032 * following run, then merge the first part with the existing
2036 size_t splitsize = (oldsize + followsize <= size + extra)
2037 ? followsize : size + extra - oldsize;
2038 arena_run_split_large(arena, (arena_run_t *)((uintptr_t)chunk +
2039 ((pageind+npages) << LG_PAGE)), splitsize, zero);
2041 size = oldsize + splitsize;
2042 npages = size >> LG_PAGE;
2045 * Mark the extended run as dirty if either portion of the run
2046 * was dirty before allocation. This is rather pedantic,
2047 * because there's not actually any sequence of events that
2048 * could cause the resulting run to be passed to
2049 * arena_run_dalloc() with the dirty argument set to false
2050 * (which is when dirty flag consistency would really matter).
2052 flag_dirty = arena_mapbits_dirty_get(chunk, pageind) |
2053 arena_mapbits_dirty_get(chunk, pageind+npages-1);
2054 arena_mapbits_large_set(chunk, pageind, size, flag_dirty);
2055 arena_mapbits_large_set(chunk, pageind+npages-1, 0, flag_dirty);
2058 arena->stats.ndalloc_large++;
2059 arena->stats.allocated_large -= oldsize;
2060 arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++;
2061 arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--;
2063 arena->stats.nmalloc_large++;
2064 arena->stats.nrequests_large++;
2065 arena->stats.allocated_large += size;
2066 arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
2067 arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
2068 arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
2070 malloc_mutex_unlock(&arena->lock);
2073 malloc_mutex_unlock(&arena->lock);
2079 #undef arena_ralloc_junk_large
2080 #define arena_ralloc_junk_large JEMALLOC_N(arena_ralloc_junk_large_impl)
2083 arena_ralloc_junk_large(void *ptr, size_t old_usize, size_t usize)
2086 if (config_fill && opt_junk) {
2087 memset((void *)((uintptr_t)ptr + usize), 0x5a,
2092 #undef arena_ralloc_junk_large
2093 #define arena_ralloc_junk_large JEMALLOC_N(arena_ralloc_junk_large)
2094 arena_ralloc_junk_large_t *arena_ralloc_junk_large =
2095 JEMALLOC_N(arena_ralloc_junk_large_impl);
2099 * Try to resize a large allocation, in order to avoid copying. This will
2100 * always fail if growing an object, and the following run is already in use.
2103 arena_ralloc_large(void *ptr, size_t oldsize, size_t size, size_t extra,
2108 psize = PAGE_CEILING(size + extra);
2109 if (psize == oldsize) {
2110 /* Same size class. */
2113 arena_chunk_t *chunk;
2116 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
2117 arena = chunk->arena;
2119 if (psize < oldsize) {
2120 /* Fill before shrinking in order avoid a race. */
2121 arena_ralloc_junk_large(ptr, oldsize, psize);
2122 arena_ralloc_large_shrink(arena, chunk, ptr, oldsize,
2126 bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
2127 oldsize, PAGE_CEILING(size),
2128 psize - PAGE_CEILING(size), zero);
2129 if (config_fill && ret == false && zero == false) {
2131 memset((void *)((uintptr_t)ptr +
2132 oldsize), 0xa5, isalloc(ptr,
2133 config_prof) - oldsize);
2134 } else if (opt_zero) {
2135 memset((void *)((uintptr_t)ptr +
2136 oldsize), 0, isalloc(ptr,
2137 config_prof) - oldsize);
2146 arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra,
2151 * Avoid moving the allocation if the size class can be left the same.
2153 if (oldsize <= arena_maxclass) {
2154 if (oldsize <= SMALL_MAXCLASS) {
2155 assert(arena_bin_info[SMALL_SIZE2BIN(oldsize)].reg_size
2157 if ((size + extra <= SMALL_MAXCLASS &&
2158 SMALL_SIZE2BIN(size + extra) ==
2159 SMALL_SIZE2BIN(oldsize)) || (size <= oldsize &&
2160 size + extra >= oldsize))
2163 assert(size <= arena_maxclass);
2164 if (size + extra > SMALL_MAXCLASS) {
2165 if (arena_ralloc_large(ptr, oldsize, size,
2166 extra, zero) == false)
2172 /* Reallocation would require a move. */
2177 arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
2178 size_t extra, size_t alignment, bool zero, bool try_tcache_alloc,
2179 bool try_tcache_dalloc)
2184 /* Try to avoid moving the allocation. */
2185 if (arena_ralloc_no_move(ptr, oldsize, size, extra, zero) == false)
2189 * size and oldsize are different enough that we need to move the
2190 * object. In that case, fall back to allocating new space and
2193 if (alignment != 0) {
2194 size_t usize = sa2u(size + extra, alignment);
2197 ret = ipalloct(usize, alignment, zero, try_tcache_alloc, arena);
2199 ret = arena_malloc(arena, size + extra, zero, try_tcache_alloc);
2204 /* Try again, this time without extra. */
2205 if (alignment != 0) {
2206 size_t usize = sa2u(size, alignment);
2209 ret = ipalloct(usize, alignment, zero, try_tcache_alloc,
2212 ret = arena_malloc(arena, size, zero, try_tcache_alloc);
2218 /* Junk/zero-filling were already done by ipalloc()/arena_malloc(). */
2221 * Copy at most size bytes (not size+extra), since the caller has no
2222 * expectation that the extra bytes will be reliably preserved.
2224 copysize = (size < oldsize) ? size : oldsize;
2225 VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize);
2226 memcpy(ret, ptr, copysize);
2227 iqalloct(ptr, try_tcache_dalloc);
2232 arena_dss_prec_get(arena_t *arena)
2236 malloc_mutex_lock(&arena->lock);
2237 ret = arena->dss_prec;
2238 malloc_mutex_unlock(&arena->lock);
2243 arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec)
2246 malloc_mutex_lock(&arena->lock);
2247 arena->dss_prec = dss_prec;
2248 malloc_mutex_unlock(&arena->lock);
2252 arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
2253 size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats,
2254 malloc_large_stats_t *lstats)
2258 malloc_mutex_lock(&arena->lock);
2259 *dss = dss_prec_names[arena->dss_prec];
2260 *nactive += arena->nactive;
2261 *ndirty += arena->ndirty;
2263 astats->mapped += arena->stats.mapped;
2264 astats->npurge += arena->stats.npurge;
2265 astats->nmadvise += arena->stats.nmadvise;
2266 astats->purged += arena->stats.purged;
2267 astats->allocated_large += arena->stats.allocated_large;
2268 astats->nmalloc_large += arena->stats.nmalloc_large;
2269 astats->ndalloc_large += arena->stats.ndalloc_large;
2270 astats->nrequests_large += arena->stats.nrequests_large;
2272 for (i = 0; i < nlclasses; i++) {
2273 lstats[i].nmalloc += arena->stats.lstats[i].nmalloc;
2274 lstats[i].ndalloc += arena->stats.lstats[i].ndalloc;
2275 lstats[i].nrequests += arena->stats.lstats[i].nrequests;
2276 lstats[i].curruns += arena->stats.lstats[i].curruns;
2278 malloc_mutex_unlock(&arena->lock);
2280 for (i = 0; i < NBINS; i++) {
2281 arena_bin_t *bin = &arena->bins[i];
2283 malloc_mutex_lock(&bin->lock);
2284 bstats[i].allocated += bin->stats.allocated;
2285 bstats[i].nmalloc += bin->stats.nmalloc;
2286 bstats[i].ndalloc += bin->stats.ndalloc;
2287 bstats[i].nrequests += bin->stats.nrequests;
2288 if (config_tcache) {
2289 bstats[i].nfills += bin->stats.nfills;
2290 bstats[i].nflushes += bin->stats.nflushes;
2292 bstats[i].nruns += bin->stats.nruns;
2293 bstats[i].reruns += bin->stats.reruns;
2294 bstats[i].curruns += bin->stats.curruns;
2295 malloc_mutex_unlock(&bin->lock);
2300 arena_new(arena_t *arena, unsigned ind)
2306 arena->nthreads = 0;
2308 if (malloc_mutex_init(&arena->lock))
2312 memset(&arena->stats, 0, sizeof(arena_stats_t));
2313 arena->stats.lstats =
2314 (malloc_large_stats_t *)base_alloc(nlclasses *
2315 sizeof(malloc_large_stats_t));
2316 if (arena->stats.lstats == NULL)
2318 memset(arena->stats.lstats, 0, nlclasses *
2319 sizeof(malloc_large_stats_t));
2321 ql_new(&arena->tcache_ql);
2325 arena->prof_accumbytes = 0;
2327 arena->dss_prec = chunk_dss_prec_get();
2329 /* Initialize chunks. */
2330 arena_chunk_dirty_new(&arena->chunks_dirty);
2331 arena->spare = NULL;
2335 arena->npurgatory = 0;
2337 arena_avail_tree_new(&arena->runs_avail);
2339 /* Initialize bins. */
2340 for (i = 0; i < NBINS; i++) {
2341 bin = &arena->bins[i];
2342 if (malloc_mutex_init(&bin->lock))
2345 arena_run_tree_new(&bin->runs);
2347 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
2354 * Calculate bin_info->run_size such that it meets the following constraints:
2356 * *) bin_info->run_size >= min_run_size
2357 * *) bin_info->run_size <= arena_maxclass
2358 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
2359 * *) bin_info->nregs <= RUN_MAXREGS
2361 * bin_info->nregs, bin_info->bitmap_offset, and bin_info->reg0_offset are also
2362 * calculated here, since these settings are all interdependent.
2365 bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
2368 size_t try_run_size, good_run_size;
2369 uint32_t try_nregs, good_nregs;
2370 uint32_t try_hdr_size, good_hdr_size;
2371 uint32_t try_bitmap_offset, good_bitmap_offset;
2372 uint32_t try_ctx0_offset, good_ctx0_offset;
2373 uint32_t try_redzone0_offset, good_redzone0_offset;
2375 assert(min_run_size >= PAGE);
2376 assert(min_run_size <= arena_maxclass);
2379 * Determine redzone size based on minimum alignment and minimum
2380 * redzone size. Add padding to the end of the run if it is needed to
2381 * align the regions. The padding allows each redzone to be half the
2382 * minimum alignment; without the padding, each redzone would have to
2383 * be twice as large in order to maintain alignment.
2385 if (config_fill && opt_redzone) {
2386 size_t align_min = ZU(1) << (ffs(bin_info->reg_size) - 1);
2387 if (align_min <= REDZONE_MINSIZE) {
2388 bin_info->redzone_size = REDZONE_MINSIZE;
2391 bin_info->redzone_size = align_min >> 1;
2392 pad_size = bin_info->redzone_size;
2395 bin_info->redzone_size = 0;
2398 bin_info->reg_interval = bin_info->reg_size +
2399 (bin_info->redzone_size << 1);
2402 * Calculate known-valid settings before entering the run_size
2403 * expansion loop, so that the first part of the loop always copies
2406 * The do..while loop iteratively reduces the number of regions until
2407 * the run header and the regions no longer overlap. A closed formula
2408 * would be quite messy, since there is an interdependency between the
2409 * header's mask length and the number of regions.
2411 try_run_size = min_run_size;
2412 try_nregs = ((try_run_size - sizeof(arena_run_t)) /
2413 bin_info->reg_interval)
2414 + 1; /* Counter-act try_nregs-- in loop. */
2415 if (try_nregs > RUN_MAXREGS) {
2416 try_nregs = RUN_MAXREGS
2417 + 1; /* Counter-act try_nregs-- in loop. */
2421 try_hdr_size = sizeof(arena_run_t);
2422 /* Pad to a long boundary. */
2423 try_hdr_size = LONG_CEILING(try_hdr_size);
2424 try_bitmap_offset = try_hdr_size;
2425 /* Add space for bitmap. */
2426 try_hdr_size += bitmap_size(try_nregs);
2427 if (config_prof && opt_prof && prof_promote == false) {
2428 /* Pad to a quantum boundary. */
2429 try_hdr_size = QUANTUM_CEILING(try_hdr_size);
2430 try_ctx0_offset = try_hdr_size;
2431 /* Add space for one (prof_ctx_t *) per region. */
2432 try_hdr_size += try_nregs * sizeof(prof_ctx_t *);
2434 try_ctx0_offset = 0;
2435 try_redzone0_offset = try_run_size - (try_nregs *
2436 bin_info->reg_interval) - pad_size;
2437 } while (try_hdr_size > try_redzone0_offset);
2439 /* run_size expansion loop. */
2442 * Copy valid settings before trying more aggressive settings.
2444 good_run_size = try_run_size;
2445 good_nregs = try_nregs;
2446 good_hdr_size = try_hdr_size;
2447 good_bitmap_offset = try_bitmap_offset;
2448 good_ctx0_offset = try_ctx0_offset;
2449 good_redzone0_offset = try_redzone0_offset;
2451 /* Try more aggressive settings. */
2452 try_run_size += PAGE;
2453 try_nregs = ((try_run_size - sizeof(arena_run_t) - pad_size) /
2454 bin_info->reg_interval)
2455 + 1; /* Counter-act try_nregs-- in loop. */
2456 if (try_nregs > RUN_MAXREGS) {
2457 try_nregs = RUN_MAXREGS
2458 + 1; /* Counter-act try_nregs-- in loop. */
2462 try_hdr_size = sizeof(arena_run_t);
2463 /* Pad to a long boundary. */
2464 try_hdr_size = LONG_CEILING(try_hdr_size);
2465 try_bitmap_offset = try_hdr_size;
2466 /* Add space for bitmap. */
2467 try_hdr_size += bitmap_size(try_nregs);
2468 if (config_prof && opt_prof && prof_promote == false) {
2469 /* Pad to a quantum boundary. */
2470 try_hdr_size = QUANTUM_CEILING(try_hdr_size);
2471 try_ctx0_offset = try_hdr_size;
2473 * Add space for one (prof_ctx_t *) per region.
2475 try_hdr_size += try_nregs *
2476 sizeof(prof_ctx_t *);
2478 try_redzone0_offset = try_run_size - (try_nregs *
2479 bin_info->reg_interval) - pad_size;
2480 } while (try_hdr_size > try_redzone0_offset);
2481 } while (try_run_size <= arena_maxclass
2482 && RUN_MAX_OVRHD * (bin_info->reg_interval << 3) >
2484 && (try_redzone0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size
2485 && try_nregs < RUN_MAXREGS);
2487 assert(good_hdr_size <= good_redzone0_offset);
2489 /* Copy final settings. */
2490 bin_info->run_size = good_run_size;
2491 bin_info->nregs = good_nregs;
2492 bin_info->bitmap_offset = good_bitmap_offset;
2493 bin_info->ctx0_offset = good_ctx0_offset;
2494 bin_info->reg0_offset = good_redzone0_offset + bin_info->redzone_size;
2496 assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs
2497 * bin_info->reg_interval) + pad_size == bin_info->run_size);
2499 return (good_run_size);
2505 arena_bin_info_t *bin_info;
2506 size_t prev_run_size = PAGE;
2508 #define SIZE_CLASS(bin, delta, size) \
2509 bin_info = &arena_bin_info[bin]; \
2510 bin_info->reg_size = size; \
2511 prev_run_size = bin_info_run_size_calc(bin_info, prev_run_size);\
2512 bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
2524 * Compute the header size such that it is large enough to contain the
2525 * page map. The page map is biased to omit entries for the header
2526 * itself, so some iteration is necessary to compute the map bias.
2528 * 1) Compute safe header_size and map_bias values that include enough
2529 * space for an unbiased page map.
2530 * 2) Refine map_bias based on (1) to omit the header pages in the page
2531 * map. The resulting map_bias may be one too small.
2532 * 3) Refine map_bias based on (2). The result will be >= the result
2533 * from (2), and will always be correct.
2536 for (i = 0; i < 3; i++) {
2537 header_size = offsetof(arena_chunk_t, map) +
2538 (sizeof(arena_chunk_map_t) * (chunk_npages-map_bias));
2539 map_bias = (header_size >> LG_PAGE) + ((header_size & PAGE_MASK)
2542 assert(map_bias > 0);
2544 arena_maxclass = chunksize - (map_bias << LG_PAGE);
2550 arena_prefork(arena_t *arena)
2554 malloc_mutex_prefork(&arena->lock);
2555 for (i = 0; i < NBINS; i++)
2556 malloc_mutex_prefork(&arena->bins[i].lock);
2560 arena_postfork_parent(arena_t *arena)
2564 for (i = 0; i < NBINS; i++)
2565 malloc_mutex_postfork_parent(&arena->bins[i].lock);
2566 malloc_mutex_postfork_parent(&arena->lock);
2570 arena_postfork_child(arena_t *arena)
2574 for (i = 0; i < NBINS; i++)
2575 malloc_mutex_postfork_child(&arena->bins[i].lock);
2576 malloc_mutex_postfork_child(&arena->lock);