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 /******************************************************************************/
41 /* Function prototypes for non-inline static functions. */
43 static void arena_avail_insert(arena_t
*arena
, arena_chunk_t
*chunk
,
44 size_t pageind
, size_t npages
, bool maybe_adjac_pred
,
45 bool maybe_adjac_succ
);
46 static void arena_avail_remove(arena_t
*arena
, arena_chunk_t
*chunk
,
47 size_t pageind
, size_t npages
, bool maybe_adjac_pred
,
48 bool maybe_adjac_succ
);
49 static void arena_run_split(arena_t
*arena
, arena_run_t
*run
, size_t size
,
50 bool large
, size_t binind
, bool zero
);
51 static arena_chunk_t
*arena_chunk_alloc(arena_t
*arena
);
52 static void arena_chunk_dealloc(arena_t
*arena
, arena_chunk_t
*chunk
);
53 static arena_run_t
*arena_run_alloc_helper(arena_t
*arena
, size_t size
,
54 bool large
, size_t binind
, bool zero
);
55 static arena_run_t
*arena_run_alloc(arena_t
*arena
, size_t size
, bool large
,
56 size_t binind
, bool zero
);
57 static arena_chunk_t
*chunks_dirty_iter_cb(arena_chunk_tree_t
*tree
,
58 arena_chunk_t
*chunk
, void *arg
);
59 static void arena_purge(arena_t
*arena
, bool all
);
60 static void arena_run_dalloc(arena_t
*arena
, arena_run_t
*run
, bool dirty
,
62 static void arena_run_trim_head(arena_t
*arena
, arena_chunk_t
*chunk
,
63 arena_run_t
*run
, size_t oldsize
, size_t newsize
);
64 static void arena_run_trim_tail(arena_t
*arena
, arena_chunk_t
*chunk
,
65 arena_run_t
*run
, size_t oldsize
, size_t newsize
, bool dirty
);
66 static arena_run_t
*arena_bin_runs_first(arena_bin_t
*bin
);
67 static void arena_bin_runs_insert(arena_bin_t
*bin
, arena_run_t
*run
);
68 static void arena_bin_runs_remove(arena_bin_t
*bin
, arena_run_t
*run
);
69 static arena_run_t
*arena_bin_nonfull_run_tryget(arena_bin_t
*bin
);
70 static arena_run_t
*arena_bin_nonfull_run_get(arena_t
*arena
, arena_bin_t
*bin
);
71 static void *arena_bin_malloc_hard(arena_t
*arena
, arena_bin_t
*bin
);
72 static void arena_dissociate_bin_run(arena_chunk_t
*chunk
, arena_run_t
*run
,
74 static void arena_dalloc_bin_run(arena_t
*arena
, arena_chunk_t
*chunk
,
75 arena_run_t
*run
, arena_bin_t
*bin
);
76 static void arena_bin_lower_run(arena_t
*arena
, arena_chunk_t
*chunk
,
77 arena_run_t
*run
, arena_bin_t
*bin
);
78 static void arena_ralloc_large_shrink(arena_t
*arena
, arena_chunk_t
*chunk
,
79 void *ptr
, size_t oldsize
, size_t size
);
80 static bool arena_ralloc_large_grow(arena_t
*arena
, arena_chunk_t
*chunk
,
81 void *ptr
, size_t oldsize
, size_t size
, size_t extra
, bool zero
);
82 static bool arena_ralloc_large(void *ptr
, size_t oldsize
, size_t size
,
83 size_t extra
, bool zero
);
84 static size_t bin_info_run_size_calc(arena_bin_info_t
*bin_info
,
86 static void bin_info_init(void);
88 /******************************************************************************/
91 arena_run_comp(arena_chunk_map_t
*a
, arena_chunk_map_t
*b
)
93 uintptr_t a_mapelm
= (uintptr_t)a
;
94 uintptr_t b_mapelm
= (uintptr_t)b
;
99 return ((a_mapelm
> b_mapelm
) - (a_mapelm
< b_mapelm
));
102 /* Generate red-black tree functions. */
103 rb_gen(static UNUSED
, arena_run_tree_
, arena_run_tree_t
, arena_chunk_map_t
,
104 u
.rb_link
, arena_run_comp
)
107 arena_avail_comp(arena_chunk_map_t
*a
, arena_chunk_map_t
*b
)
110 size_t a_size
= a
->bits
& ~PAGE_MASK
;
111 size_t b_size
= b
->bits
& ~PAGE_MASK
;
113 ret
= (a_size
> b_size
) - (a_size
< b_size
);
115 uintptr_t a_mapelm
, b_mapelm
;
117 if ((a
->bits
& CHUNK_MAP_KEY
) != CHUNK_MAP_KEY
)
118 a_mapelm
= (uintptr_t)a
;
121 * Treat keys as though they are lower than anything
126 b_mapelm
= (uintptr_t)b
;
128 ret
= (a_mapelm
> b_mapelm
) - (a_mapelm
< b_mapelm
);
134 /* Generate red-black tree functions. */
135 rb_gen(static UNUSED
, arena_avail_tree_
, arena_avail_tree_t
, arena_chunk_map_t
,
136 u
.rb_link
, arena_avail_comp
)
139 arena_chunk_dirty_comp(arena_chunk_t
*a
, arena_chunk_t
*b
)
146 * Short-circuit for self comparison. The following comparison code
147 * would come to the same result, but at the cost of executing the slow
154 * Order such that chunks with higher fragmentation are "less than"
155 * those with lower fragmentation -- purging order is from "least" to
156 * "greatest". Fragmentation is measured as:
158 * mean current avail run size
159 * --------------------------------
160 * mean defragmented avail run size
164 * nruns_avail nruns_avail-nruns_adjac
165 * = ========================= = -----------------------
167 * -----------------------
168 * nruns_avail-nruns_adjac
170 * The following code multiplies away the denominator prior to
171 * comparison, in order to avoid division.
175 size_t a_val
= (a
->nruns_avail
- a
->nruns_adjac
) *
177 size_t b_val
= (b
->nruns_avail
- b
->nruns_adjac
) *
186 * Break ties by chunk address. For fragmented chunks, report lower
187 * addresses as "lower", so that fragmentation reduction happens first
188 * at lower addresses. However, use the opposite ordering for
189 * unfragmented chunks, in order to increase the chances of
190 * re-allocating dirty runs.
193 uintptr_t a_chunk
= (uintptr_t)a
;
194 uintptr_t b_chunk
= (uintptr_t)b
;
195 int ret
= ((a_chunk
> b_chunk
) - (a_chunk
< b_chunk
));
196 if (a
->nruns_adjac
== 0) {
197 assert(b
->nruns_adjac
== 0);
204 /* Generate red-black tree functions. */
205 rb_gen(static UNUSED
, arena_chunk_dirty_
, arena_chunk_tree_t
, arena_chunk_t
,
206 dirty_link
, arena_chunk_dirty_comp
)
209 arena_avail_adjac_pred(arena_chunk_t
*chunk
, size_t pageind
)
213 if (pageind
-1 < map_bias
)
216 ret
= (arena_mapbits_allocated_get(chunk
, pageind
-1) == 0);
217 assert(ret
== false || arena_mapbits_dirty_get(chunk
,
218 pageind
-1) != arena_mapbits_dirty_get(chunk
, pageind
));
224 arena_avail_adjac_succ(arena_chunk_t
*chunk
, size_t pageind
, size_t npages
)
228 if (pageind
+npages
== chunk_npages
)
231 assert(pageind
+npages
< chunk_npages
);
232 ret
= (arena_mapbits_allocated_get(chunk
, pageind
+npages
) == 0);
233 assert(ret
== false || arena_mapbits_dirty_get(chunk
, pageind
)
234 != arena_mapbits_dirty_get(chunk
, pageind
+npages
));
240 arena_avail_adjac(arena_chunk_t
*chunk
, size_t pageind
, size_t npages
)
243 return (arena_avail_adjac_pred(chunk
, pageind
) ||
244 arena_avail_adjac_succ(chunk
, pageind
, npages
));
248 arena_avail_insert(arena_t
*arena
, arena_chunk_t
*chunk
, size_t pageind
,
249 size_t npages
, bool maybe_adjac_pred
, bool maybe_adjac_succ
)
252 assert(npages
== (arena_mapbits_unallocated_size_get(chunk
, pageind
) >>
256 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
257 * removed and reinserted even if the run to be inserted is clean.
259 if (chunk
->ndirty
!= 0)
260 arena_chunk_dirty_remove(&arena
->chunks_dirty
, chunk
);
262 if (maybe_adjac_pred
&& arena_avail_adjac_pred(chunk
, pageind
))
263 chunk
->nruns_adjac
++;
264 if (maybe_adjac_succ
&& arena_avail_adjac_succ(chunk
, pageind
, npages
))
265 chunk
->nruns_adjac
++;
266 chunk
->nruns_avail
++;
267 assert(chunk
->nruns_avail
> chunk
->nruns_adjac
);
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_insert(&arena
->runs_avail
, arena_mapp_get(chunk
,
281 arena_avail_remove(arena_t
*arena
, arena_chunk_t
*chunk
, size_t pageind
,
282 size_t npages
, bool maybe_adjac_pred
, bool maybe_adjac_succ
)
285 assert(npages
== (arena_mapbits_unallocated_size_get(chunk
, pageind
) >>
289 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
290 * removed and reinserted even if the run to be removed is clean.
292 if (chunk
->ndirty
!= 0)
293 arena_chunk_dirty_remove(&arena
->chunks_dirty
, chunk
);
295 if (maybe_adjac_pred
&& arena_avail_adjac_pred(chunk
, pageind
))
296 chunk
->nruns_adjac
--;
297 if (maybe_adjac_succ
&& arena_avail_adjac_succ(chunk
, pageind
, npages
))
298 chunk
->nruns_adjac
--;
299 chunk
->nruns_avail
--;
300 assert(chunk
->nruns_avail
> chunk
->nruns_adjac
|| (chunk
->nruns_avail
301 == 0 && chunk
->nruns_adjac
== 0));
303 if (arena_mapbits_dirty_get(chunk
, pageind
) != 0) {
304 arena
->ndirty
-= npages
;
305 chunk
->ndirty
-= npages
;
307 if (chunk
->ndirty
!= 0)
308 arena_chunk_dirty_insert(&arena
->chunks_dirty
, chunk
);
310 arena_avail_tree_remove(&arena
->runs_avail
, arena_mapp_get(chunk
,
315 arena_run_reg_alloc(arena_run_t
*run
, arena_bin_info_t
*bin_info
)
319 bitmap_t
*bitmap
= (bitmap_t
*)((uintptr_t)run
+
320 (uintptr_t)bin_info
->bitmap_offset
);
322 assert(run
->nfree
> 0);
323 assert(bitmap_full(bitmap
, &bin_info
->bitmap_info
) == false);
325 regind
= bitmap_sfu(bitmap
, &bin_info
->bitmap_info
);
326 ret
= (void *)((uintptr_t)run
+ (uintptr_t)bin_info
->reg0_offset
+
327 (uintptr_t)(bin_info
->reg_interval
* regind
));
329 if (regind
== run
->nextind
)
331 assert(regind
< run
->nextind
);
336 arena_run_reg_dalloc(arena_run_t
*run
, void *ptr
)
338 arena_chunk_t
*chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
339 size_t pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> LG_PAGE
;
340 size_t mapbits
= arena_mapbits_get(chunk
, pageind
);
341 size_t binind
= arena_ptr_small_binind_get(ptr
, mapbits
);
342 arena_bin_info_t
*bin_info
= &arena_bin_info
[binind
];
343 unsigned regind
= arena_run_regind(run
, bin_info
, ptr
);
344 bitmap_t
*bitmap
= (bitmap_t
*)((uintptr_t)run
+
345 (uintptr_t)bin_info
->bitmap_offset
);
347 assert(run
->nfree
< bin_info
->nregs
);
348 /* Freeing an interior pointer can cause assertion failure. */
349 assert(((uintptr_t)ptr
- ((uintptr_t)run
+
350 (uintptr_t)bin_info
->reg0_offset
)) %
351 (uintptr_t)bin_info
->reg_interval
== 0);
352 assert((uintptr_t)ptr
>= (uintptr_t)run
+
353 (uintptr_t)bin_info
->reg0_offset
);
354 /* Freeing an unallocated pointer can cause assertion failure. */
355 assert(bitmap_get(bitmap
, &bin_info
->bitmap_info
, regind
));
357 bitmap_unset(bitmap
, &bin_info
->bitmap_info
, regind
);
362 arena_chunk_validate_zeroed(arena_chunk_t
*chunk
, size_t run_ind
)
365 UNUSED
size_t *p
= (size_t *)((uintptr_t)chunk
+ (run_ind
<< LG_PAGE
));
367 for (i
= 0; i
< PAGE
/ sizeof(size_t); i
++)
372 arena_run_split(arena_t
*arena
, arena_run_t
*run
, size_t size
, bool large
,
373 size_t binind
, bool zero
)
375 arena_chunk_t
*chunk
;
376 size_t run_ind
, total_pages
, need_pages
, rem_pages
, i
;
379 assert((large
&& binind
== BININD_INVALID
) || (large
== false && binind
382 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
383 run_ind
= (unsigned)(((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
);
384 flag_dirty
= arena_mapbits_dirty_get(chunk
, run_ind
);
385 total_pages
= arena_mapbits_unallocated_size_get(chunk
, run_ind
) >>
387 assert(arena_mapbits_dirty_get(chunk
, run_ind
+total_pages
-1) ==
389 need_pages
= (size
>> LG_PAGE
);
390 assert(need_pages
> 0);
391 assert(need_pages
<= total_pages
);
392 rem_pages
= total_pages
- need_pages
;
394 arena_avail_remove(arena
, chunk
, run_ind
, total_pages
, true, true);
397 * Update stats_cactive if nactive is crossing a chunk
400 size_t cactive_diff
= CHUNK_CEILING((arena
->nactive
+
401 need_pages
) << LG_PAGE
) - CHUNK_CEILING(arena
->nactive
<<
403 if (cactive_diff
!= 0)
404 stats_cactive_add(cactive_diff
);
406 arena
->nactive
+= need_pages
;
408 /* Keep track of trailing unused pages for later use. */
410 if (flag_dirty
!= 0) {
411 arena_mapbits_unallocated_set(chunk
, run_ind
+need_pages
,
412 (rem_pages
<< LG_PAGE
), CHUNK_MAP_DIRTY
);
413 arena_mapbits_unallocated_set(chunk
,
414 run_ind
+total_pages
-1, (rem_pages
<< LG_PAGE
),
417 arena_mapbits_unallocated_set(chunk
, run_ind
+need_pages
,
418 (rem_pages
<< LG_PAGE
),
419 arena_mapbits_unzeroed_get(chunk
,
420 run_ind
+need_pages
));
421 arena_mapbits_unallocated_set(chunk
,
422 run_ind
+total_pages
-1, (rem_pages
<< LG_PAGE
),
423 arena_mapbits_unzeroed_get(chunk
,
424 run_ind
+total_pages
-1));
426 arena_avail_insert(arena
, chunk
, run_ind
+need_pages
, rem_pages
,
431 * Update the page map separately for large vs. small runs, since it is
432 * possible to avoid iteration for large mallocs.
436 if (flag_dirty
== 0) {
438 * The run is clean, so some pages may be
439 * zeroed (i.e. never before touched).
441 for (i
= 0; i
< need_pages
; i
++) {
442 if (arena_mapbits_unzeroed_get(chunk
,
444 VALGRIND_MAKE_MEM_UNDEFINED(
446 chunk
+ ((run_ind
+i
) <<
448 memset((void *)((uintptr_t)
449 chunk
+ ((run_ind
+i
) <<
451 } else if (config_debug
) {
452 VALGRIND_MAKE_MEM_DEFINED(
454 chunk
+ ((run_ind
+i
) <<
456 arena_chunk_validate_zeroed(
462 * The run is dirty, so all pages must be
465 VALGRIND_MAKE_MEM_UNDEFINED((void
466 *)((uintptr_t)chunk
+ (run_ind
<<
467 LG_PAGE
)), (need_pages
<< LG_PAGE
));
468 memset((void *)((uintptr_t)chunk
+ (run_ind
<<
469 LG_PAGE
)), 0, (need_pages
<< LG_PAGE
));
474 * Set the last element first, in case the run only contains one
475 * page (i.e. both statements set the same element).
477 arena_mapbits_large_set(chunk
, run_ind
+need_pages
-1, 0,
479 arena_mapbits_large_set(chunk
, run_ind
, size
, flag_dirty
);
481 assert(zero
== false);
483 * Propagate the dirty and unzeroed flags to the allocated
484 * small run, so that arena_dalloc_bin_run() has the ability to
485 * conditionally trim clean pages.
487 arena_mapbits_small_set(chunk
, run_ind
, 0, binind
, flag_dirty
);
489 * The first page will always be dirtied during small run
490 * initialization, so a validation failure here would not
491 * actually cause an observable failure.
493 if (config_debug
&& flag_dirty
== 0 &&
494 arena_mapbits_unzeroed_get(chunk
, run_ind
) == 0)
495 arena_chunk_validate_zeroed(chunk
, run_ind
);
496 for (i
= 1; i
< need_pages
- 1; i
++) {
497 arena_mapbits_small_set(chunk
, run_ind
+i
, i
, binind
, 0);
498 if (config_debug
&& flag_dirty
== 0 &&
499 arena_mapbits_unzeroed_get(chunk
, run_ind
+i
) == 0)
500 arena_chunk_validate_zeroed(chunk
, run_ind
+i
);
502 arena_mapbits_small_set(chunk
, run_ind
+need_pages
-1,
503 need_pages
-1, binind
, flag_dirty
);
504 if (config_debug
&& flag_dirty
== 0 &&
505 arena_mapbits_unzeroed_get(chunk
, run_ind
+need_pages
-1) ==
507 arena_chunk_validate_zeroed(chunk
,
508 run_ind
+need_pages
-1);
513 static arena_chunk_t
*
514 arena_chunk_alloc(arena_t
*arena
)
516 arena_chunk_t
*chunk
;
519 if (arena
->spare
!= NULL
) {
520 chunk
= arena
->spare
;
523 assert(arena_mapbits_allocated_get(chunk
, map_bias
) == 0);
524 assert(arena_mapbits_allocated_get(chunk
, chunk_npages
-1) == 0);
525 assert(arena_mapbits_unallocated_size_get(chunk
, map_bias
) ==
527 assert(arena_mapbits_unallocated_size_get(chunk
,
528 chunk_npages
-1) == arena_maxclass
);
529 assert(arena_mapbits_dirty_get(chunk
, map_bias
) ==
530 arena_mapbits_dirty_get(chunk
, chunk_npages
-1));
536 malloc_mutex_unlock(&arena
->lock
);
537 chunk
= (arena_chunk_t
*)chunk_alloc(chunksize
, chunksize
,
538 false, &zero
, arena
->dss_prec
);
539 malloc_mutex_lock(&arena
->lock
);
543 arena
->stats
.mapped
+= chunksize
;
545 chunk
->arena
= arena
;
548 * Claim that no pages are in use, since the header is merely
553 chunk
->nruns_avail
= 0;
554 chunk
->nruns_adjac
= 0;
557 * Initialize the map to contain one maximal free untouched run.
558 * Mark the pages as zeroed iff chunk_alloc() returned a zeroed
561 unzeroed
= zero
? 0 : CHUNK_MAP_UNZEROED
;
562 arena_mapbits_unallocated_set(chunk
, map_bias
, arena_maxclass
,
565 * There is no need to initialize the internal page map entries
566 * unless the chunk is not zeroed.
569 for (i
= map_bias
+1; i
< chunk_npages
-1; i
++)
570 arena_mapbits_unzeroed_set(chunk
, i
, unzeroed
);
571 } else if (config_debug
) {
572 for (i
= map_bias
+1; i
< chunk_npages
-1; i
++) {
573 assert(arena_mapbits_unzeroed_get(chunk
, i
) ==
577 arena_mapbits_unallocated_set(chunk
, chunk_npages
-1,
578 arena_maxclass
, unzeroed
);
581 /* Insert the run into the runs_avail tree. */
582 arena_avail_insert(arena
, chunk
, map_bias
, chunk_npages
-map_bias
,
589 arena_chunk_dealloc(arena_t
*arena
, arena_chunk_t
*chunk
)
591 assert(arena_mapbits_allocated_get(chunk
, map_bias
) == 0);
592 assert(arena_mapbits_allocated_get(chunk
, chunk_npages
-1) == 0);
593 assert(arena_mapbits_unallocated_size_get(chunk
, map_bias
) ==
595 assert(arena_mapbits_unallocated_size_get(chunk
, chunk_npages
-1) ==
597 assert(arena_mapbits_dirty_get(chunk
, map_bias
) ==
598 arena_mapbits_dirty_get(chunk
, chunk_npages
-1));
601 * Remove run from the runs_avail tree, so that the arena does not use
604 arena_avail_remove(arena
, chunk
, map_bias
, chunk_npages
-map_bias
,
607 if (arena
->spare
!= NULL
) {
608 arena_chunk_t
*spare
= arena
->spare
;
610 arena
->spare
= chunk
;
611 malloc_mutex_unlock(&arena
->lock
);
612 chunk_dealloc((void *)spare
, chunksize
, true);
613 malloc_mutex_lock(&arena
->lock
);
615 arena
->stats
.mapped
-= chunksize
;
617 arena
->spare
= chunk
;
621 arena_run_alloc_helper(arena_t
*arena
, size_t size
, bool large
, size_t binind
,
625 arena_chunk_map_t
*mapelm
, key
;
627 key
.bits
= size
| CHUNK_MAP_KEY
;
628 mapelm
= arena_avail_tree_nsearch(&arena
->runs_avail
, &key
);
629 if (mapelm
!= NULL
) {
630 arena_chunk_t
*run_chunk
= CHUNK_ADDR2BASE(mapelm
);
631 size_t pageind
= (((uintptr_t)mapelm
-
632 (uintptr_t)run_chunk
->map
) / sizeof(arena_chunk_map_t
))
635 run
= (arena_run_t
*)((uintptr_t)run_chunk
+ (pageind
<<
637 arena_run_split(arena
, run
, size
, large
, binind
, zero
);
645 arena_run_alloc(arena_t
*arena
, size_t size
, bool large
, size_t binind
,
648 arena_chunk_t
*chunk
;
651 assert(size
<= arena_maxclass
);
652 assert((size
& PAGE_MASK
) == 0);
653 assert((large
&& binind
== BININD_INVALID
) || (large
== false && binind
656 /* Search the arena's chunks for the lowest best fit. */
657 run
= arena_run_alloc_helper(arena
, size
, large
, binind
, zero
);
662 * No usable runs. Create a new chunk from which to allocate the run.
664 chunk
= arena_chunk_alloc(arena
);
666 run
= (arena_run_t
*)((uintptr_t)chunk
+ (map_bias
<< LG_PAGE
));
667 arena_run_split(arena
, run
, size
, large
, binind
, zero
);
672 * arena_chunk_alloc() failed, but another thread may have made
673 * sufficient memory available while this one dropped arena->lock in
674 * arena_chunk_alloc(), so search one more time.
676 return (arena_run_alloc_helper(arena
, size
, large
, binind
, zero
));
680 arena_maybe_purge(arena_t
*arena
)
682 size_t npurgeable
, threshold
;
684 /* Don't purge if the option is disabled. */
685 if (opt_lg_dirty_mult
< 0)
687 /* Don't purge if all dirty pages are already being purged. */
688 if (arena
->ndirty
<= arena
->npurgatory
)
690 npurgeable
= arena
->ndirty
- arena
->npurgatory
;
691 threshold
= (arena
->nactive
>> opt_lg_dirty_mult
);
693 * Don't purge unless the number of purgeable pages exceeds the
696 if (npurgeable
<= threshold
)
699 arena_purge(arena
, false);
703 arena_chunk_purge(arena_t
*arena
, arena_chunk_t
*chunk
, bool all
)
706 ql_head(arena_chunk_map_t
) mapelms
;
707 arena_chunk_map_t
*mapelm
;
708 size_t pageind
, npages
;
714 * If chunk is the spare, temporarily re-allocate it, 1) so that its
715 * run is reinserted into runs_avail, and 2) so that it cannot be
716 * completely discarded by another thread while arena->lock is dropped
717 * by this thread. Note that the arena_run_dalloc() call will
718 * implicitly deallocate the chunk, so no explicit action is required
719 * in this function to deallocate the chunk.
721 * Note that once a chunk contains dirty pages, it cannot again contain
722 * a single run unless 1) it is a dirty run, or 2) this function purges
723 * dirty pages and causes the transition to a single clean run. Thus
724 * (chunk == arena->spare) is possible, but it is not possible for
725 * this function to be called on the spare unless it contains a dirty
728 if (chunk
== arena
->spare
) {
729 assert(arena_mapbits_dirty_get(chunk
, map_bias
) != 0);
730 assert(arena_mapbits_dirty_get(chunk
, chunk_npages
-1) != 0);
732 arena_chunk_alloc(arena
);
736 arena
->stats
.purged
+= chunk
->ndirty
;
739 * Operate on all dirty runs if there is no clean/dirty run
742 if (chunk
->nruns_adjac
== 0)
746 * Temporarily allocate free dirty runs within chunk. If all is false,
747 * only operate on dirty runs that are fragments; otherwise operate on
750 for (pageind
= map_bias
; pageind
< chunk_npages
; pageind
+= npages
) {
751 mapelm
= arena_mapp_get(chunk
, pageind
);
752 if (arena_mapbits_allocated_get(chunk
, pageind
) == 0) {
754 arena_mapbits_unallocated_size_get(chunk
, pageind
);
756 npages
= run_size
>> LG_PAGE
;
757 assert(pageind
+ npages
<= chunk_npages
);
758 assert(arena_mapbits_dirty_get(chunk
, pageind
) ==
759 arena_mapbits_dirty_get(chunk
, pageind
+npages
-1));
761 if (arena_mapbits_dirty_get(chunk
, pageind
) != 0 &&
762 (all
|| arena_avail_adjac(chunk
, pageind
,
764 arena_run_t
*run
= (arena_run_t
*)((uintptr_t)
765 chunk
+ (uintptr_t)(pageind
<< LG_PAGE
));
767 arena_run_split(arena
, run
, run_size
, true,
768 BININD_INVALID
, false);
769 /* Append to list for later processing. */
770 ql_elm_new(mapelm
, u
.ql_link
);
771 ql_tail_insert(&mapelms
, mapelm
, u
.ql_link
);
775 if (arena_mapbits_large_get(chunk
, pageind
) != 0) {
776 npages
= arena_mapbits_large_size_get(chunk
,
780 arena_bin_info_t
*bin_info
;
781 arena_run_t
*run
= (arena_run_t
*)((uintptr_t)
782 chunk
+ (uintptr_t)(pageind
<< LG_PAGE
));
784 assert(arena_mapbits_small_runind_get(chunk
,
786 binind
= arena_bin_index(arena
, run
->bin
);
787 bin_info
= &arena_bin_info
[binind
];
788 npages
= bin_info
->run_size
>> LG_PAGE
;
792 assert(pageind
== chunk_npages
);
793 assert(chunk
->ndirty
== 0 || all
== false);
794 assert(chunk
->nruns_adjac
== 0);
796 malloc_mutex_unlock(&arena
->lock
);
800 ql_foreach(mapelm
, &mapelms
, u
.ql_link
) {
802 size_t flag_unzeroed
, i
;
804 pageind
= (((uintptr_t)mapelm
- (uintptr_t)chunk
->map
) /
805 sizeof(arena_chunk_map_t
)) + map_bias
;
806 npages
= arena_mapbits_large_size_get(chunk
, pageind
) >>
808 assert(pageind
+ npages
<= chunk_npages
);
809 unzeroed
= pages_purge((void *)((uintptr_t)chunk
+ (pageind
<<
810 LG_PAGE
)), (npages
<< LG_PAGE
));
811 flag_unzeroed
= unzeroed
? CHUNK_MAP_UNZEROED
: 0;
813 * Set the unzeroed flag for all pages, now that pages_purge()
814 * has returned whether the pages were zeroed as a side effect
815 * of purging. This chunk map modification is safe even though
816 * the arena mutex isn't currently owned by this thread,
817 * because the run is marked as allocated, thus protecting it
818 * from being modified by any other thread. As long as these
819 * writes don't perturb the first and last elements'
820 * CHUNK_MAP_ALLOCATED bits, behavior is well defined.
822 for (i
= 0; i
< npages
; i
++) {
823 arena_mapbits_unzeroed_set(chunk
, pageind
+i
,
830 malloc_mutex_lock(&arena
->lock
);
832 arena
->stats
.nmadvise
+= nmadvise
;
834 /* Deallocate runs. */
835 for (mapelm
= ql_first(&mapelms
); mapelm
!= NULL
;
836 mapelm
= ql_first(&mapelms
)) {
839 pageind
= (((uintptr_t)mapelm
- (uintptr_t)chunk
->map
) /
840 sizeof(arena_chunk_map_t
)) + map_bias
;
841 run
= (arena_run_t
*)((uintptr_t)chunk
+ (uintptr_t)(pageind
<<
843 ql_remove(&mapelms
, mapelm
, u
.ql_link
);
844 arena_run_dalloc(arena
, run
, false, true);
850 static arena_chunk_t
*
851 chunks_dirty_iter_cb(arena_chunk_tree_t
*tree
, arena_chunk_t
*chunk
, void *arg
)
853 size_t *ndirty
= (size_t *)arg
;
855 assert(chunk
->ndirty
!= 0);
856 *ndirty
+= chunk
->ndirty
;
861 arena_purge(arena_t
*arena
, bool all
)
863 arena_chunk_t
*chunk
;
868 arena_chunk_dirty_iter(&arena
->chunks_dirty
, NULL
,
869 chunks_dirty_iter_cb
, (void *)&ndirty
);
870 assert(ndirty
== arena
->ndirty
);
872 assert(arena
->ndirty
> arena
->npurgatory
|| all
);
873 assert((arena
->nactive
>> opt_lg_dirty_mult
) < (arena
->ndirty
-
874 arena
->npurgatory
) || all
);
877 arena
->stats
.npurge
++;
880 * Compute the minimum number of pages that this thread should try to
881 * purge, and add the result to arena->npurgatory. This will keep
882 * multiple threads from racing to reduce ndirty below the threshold.
885 size_t npurgeable
= arena
->ndirty
- arena
->npurgatory
;
888 size_t threshold
= (arena
->nactive
>>
891 npurgatory
= npurgeable
- threshold
;
893 npurgatory
= npurgeable
;
895 arena
->npurgatory
+= npurgatory
;
897 while (npurgatory
> 0) {
898 size_t npurgeable
, npurged
, nunpurged
;
900 /* Get next chunk with dirty pages. */
901 chunk
= arena_chunk_dirty_first(&arena
->chunks_dirty
);
904 * This thread was unable to purge as many pages as
905 * originally intended, due to races with other threads
906 * that either did some of the purging work, or re-used
909 arena
->npurgatory
-= npurgatory
;
912 npurgeable
= chunk
->ndirty
;
913 assert(npurgeable
!= 0);
915 if (npurgeable
> npurgatory
&& chunk
->nruns_adjac
== 0) {
917 * This thread will purge all the dirty pages in chunk,
918 * so set npurgatory to reflect this thread's intent to
919 * purge the pages. This tends to reduce the chances
920 * of the following scenario:
922 * 1) This thread sets arena->npurgatory such that
923 * (arena->ndirty - arena->npurgatory) is at the
925 * 2) This thread drops arena->lock.
926 * 3) Another thread causes one or more pages to be
927 * dirtied, and immediately determines that it must
930 * If this scenario *does* play out, that's okay,
931 * because all of the purging work being done really
934 arena
->npurgatory
+= npurgeable
- npurgatory
;
935 npurgatory
= npurgeable
;
939 * Keep track of how many pages are purgeable, versus how many
940 * actually get purged, and adjust counters accordingly.
942 arena
->npurgatory
-= npurgeable
;
943 npurgatory
-= npurgeable
;
944 npurged
= arena_chunk_purge(arena
, chunk
, all
);
945 nunpurged
= npurgeable
- npurged
;
946 arena
->npurgatory
+= nunpurged
;
947 npurgatory
+= nunpurged
;
952 arena_purge_all(arena_t
*arena
)
955 malloc_mutex_lock(&arena
->lock
);
956 arena_purge(arena
, true);
957 malloc_mutex_unlock(&arena
->lock
);
961 arena_run_dalloc(arena_t
*arena
, arena_run_t
*run
, bool dirty
, bool cleaned
)
963 arena_chunk_t
*chunk
;
964 size_t size
, run_ind
, run_pages
, flag_dirty
;
966 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
967 run_ind
= (size_t)(((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
);
968 assert(run_ind
>= map_bias
);
969 assert(run_ind
< chunk_npages
);
970 if (arena_mapbits_large_get(chunk
, run_ind
) != 0) {
971 size
= arena_mapbits_large_size_get(chunk
, run_ind
);
972 assert(size
== PAGE
||
973 arena_mapbits_large_size_get(chunk
,
974 run_ind
+(size
>>LG_PAGE
)-1) == 0);
976 size_t binind
= arena_bin_index(arena
, run
->bin
);
977 arena_bin_info_t
*bin_info
= &arena_bin_info
[binind
];
978 size
= bin_info
->run_size
;
980 run_pages
= (size
>> LG_PAGE
);
983 * Update stats_cactive if nactive is crossing a chunk
986 size_t cactive_diff
= CHUNK_CEILING(arena
->nactive
<< LG_PAGE
) -
987 CHUNK_CEILING((arena
->nactive
- run_pages
) << LG_PAGE
);
988 if (cactive_diff
!= 0)
989 stats_cactive_sub(cactive_diff
);
991 arena
->nactive
-= run_pages
;
994 * The run is dirty if the caller claims to have dirtied it, as well as
995 * if it was already dirty before being allocated and the caller
996 * doesn't claim to have cleaned it.
998 assert(arena_mapbits_dirty_get(chunk
, run_ind
) ==
999 arena_mapbits_dirty_get(chunk
, run_ind
+run_pages
-1));
1000 if (cleaned
== false && arena_mapbits_dirty_get(chunk
, run_ind
) != 0)
1002 flag_dirty
= dirty
? CHUNK_MAP_DIRTY
: 0;
1004 /* Mark pages as unallocated in the chunk map. */
1006 arena_mapbits_unallocated_set(chunk
, run_ind
, size
,
1008 arena_mapbits_unallocated_set(chunk
, run_ind
+run_pages
-1, size
,
1011 arena_mapbits_unallocated_set(chunk
, run_ind
, size
,
1012 arena_mapbits_unzeroed_get(chunk
, run_ind
));
1013 arena_mapbits_unallocated_set(chunk
, run_ind
+run_pages
-1, size
,
1014 arena_mapbits_unzeroed_get(chunk
, run_ind
+run_pages
-1));
1017 /* Try to coalesce forward. */
1018 if (run_ind
+ run_pages
< chunk_npages
&&
1019 arena_mapbits_allocated_get(chunk
, run_ind
+run_pages
) == 0 &&
1020 arena_mapbits_dirty_get(chunk
, run_ind
+run_pages
) == flag_dirty
) {
1021 size_t nrun_size
= arena_mapbits_unallocated_size_get(chunk
,
1023 size_t nrun_pages
= nrun_size
>> LG_PAGE
;
1026 * Remove successor from runs_avail; the coalesced run is
1029 assert(arena_mapbits_unallocated_size_get(chunk
,
1030 run_ind
+run_pages
+nrun_pages
-1) == nrun_size
);
1031 assert(arena_mapbits_dirty_get(chunk
,
1032 run_ind
+run_pages
+nrun_pages
-1) == flag_dirty
);
1033 arena_avail_remove(arena
, chunk
, run_ind
+run_pages
, nrun_pages
,
1037 run_pages
+= nrun_pages
;
1039 arena_mapbits_unallocated_size_set(chunk
, run_ind
, size
);
1040 arena_mapbits_unallocated_size_set(chunk
, run_ind
+run_pages
-1,
1044 /* Try to coalesce backward. */
1045 if (run_ind
> map_bias
&& arena_mapbits_allocated_get(chunk
, run_ind
-1)
1046 == 0 && arena_mapbits_dirty_get(chunk
, run_ind
-1) == flag_dirty
) {
1047 size_t prun_size
= arena_mapbits_unallocated_size_get(chunk
,
1049 size_t prun_pages
= prun_size
>> LG_PAGE
;
1051 run_ind
-= prun_pages
;
1054 * Remove predecessor from runs_avail; the coalesced run is
1057 assert(arena_mapbits_unallocated_size_get(chunk
, run_ind
) ==
1059 assert(arena_mapbits_dirty_get(chunk
, run_ind
) == flag_dirty
);
1060 arena_avail_remove(arena
, chunk
, run_ind
, prun_pages
, true,
1064 run_pages
+= prun_pages
;
1066 arena_mapbits_unallocated_size_set(chunk
, run_ind
, size
);
1067 arena_mapbits_unallocated_size_set(chunk
, run_ind
+run_pages
-1,
1071 /* Insert into runs_avail, now that coalescing is complete. */
1072 assert(arena_mapbits_unallocated_size_get(chunk
, run_ind
) ==
1073 arena_mapbits_unallocated_size_get(chunk
, run_ind
+run_pages
-1));
1074 assert(arena_mapbits_dirty_get(chunk
, run_ind
) ==
1075 arena_mapbits_dirty_get(chunk
, run_ind
+run_pages
-1));
1076 arena_avail_insert(arena
, chunk
, run_ind
, run_pages
, true, true);
1078 /* Deallocate chunk if it is now completely unused. */
1079 if (size
== arena_maxclass
) {
1080 assert(run_ind
== map_bias
);
1081 assert(run_pages
== (arena_maxclass
>> LG_PAGE
));
1082 arena_chunk_dealloc(arena
, chunk
);
1086 * It is okay to do dirty page processing here even if the chunk was
1087 * deallocated above, since in that case it is the spare. Waiting
1088 * until after possible chunk deallocation to do dirty processing
1089 * allows for an old spare to be fully deallocated, thus decreasing the
1090 * chances of spuriously crossing the dirty page purging threshold.
1093 arena_maybe_purge(arena
);
1097 arena_run_trim_head(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
1098 size_t oldsize
, size_t newsize
)
1100 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
;
1101 size_t head_npages
= (oldsize
- newsize
) >> LG_PAGE
;
1102 size_t flag_dirty
= arena_mapbits_dirty_get(chunk
, pageind
);
1104 assert(oldsize
> newsize
);
1107 * Update the chunk map so that arena_run_dalloc() can treat the
1108 * leading run as separately allocated. Set the last element of each
1109 * run first, in case of single-page runs.
1111 assert(arena_mapbits_large_size_get(chunk
, pageind
) == oldsize
);
1112 arena_mapbits_large_set(chunk
, pageind
+head_npages
-1, 0, flag_dirty
);
1113 arena_mapbits_large_set(chunk
, pageind
, oldsize
-newsize
, flag_dirty
);
1116 UNUSED
size_t tail_npages
= newsize
>> LG_PAGE
;
1117 assert(arena_mapbits_large_size_get(chunk
,
1118 pageind
+head_npages
+tail_npages
-1) == 0);
1119 assert(arena_mapbits_dirty_get(chunk
,
1120 pageind
+head_npages
+tail_npages
-1) == flag_dirty
);
1122 arena_mapbits_large_set(chunk
, pageind
+head_npages
, newsize
,
1125 arena_run_dalloc(arena
, run
, false, false);
1129 arena_run_trim_tail(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
1130 size_t oldsize
, size_t newsize
, bool dirty
)
1132 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
;
1133 size_t head_npages
= newsize
>> LG_PAGE
;
1134 size_t flag_dirty
= arena_mapbits_dirty_get(chunk
, pageind
);
1136 assert(oldsize
> newsize
);
1139 * Update the chunk map so that arena_run_dalloc() can treat the
1140 * trailing run as separately allocated. Set the last element of each
1141 * run first, in case of single-page runs.
1143 assert(arena_mapbits_large_size_get(chunk
, pageind
) == oldsize
);
1144 arena_mapbits_large_set(chunk
, pageind
+head_npages
-1, 0, flag_dirty
);
1145 arena_mapbits_large_set(chunk
, pageind
, newsize
, flag_dirty
);
1148 UNUSED
size_t tail_npages
= (oldsize
- newsize
) >> LG_PAGE
;
1149 assert(arena_mapbits_large_size_get(chunk
,
1150 pageind
+head_npages
+tail_npages
-1) == 0);
1151 assert(arena_mapbits_dirty_get(chunk
,
1152 pageind
+head_npages
+tail_npages
-1) == flag_dirty
);
1154 arena_mapbits_large_set(chunk
, pageind
+head_npages
, oldsize
-newsize
,
1157 arena_run_dalloc(arena
, (arena_run_t
*)((uintptr_t)run
+ newsize
),
1161 static arena_run_t
*
1162 arena_bin_runs_first(arena_bin_t
*bin
)
1164 arena_chunk_map_t
*mapelm
= arena_run_tree_first(&bin
->runs
);
1165 if (mapelm
!= NULL
) {
1166 arena_chunk_t
*chunk
;
1170 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(mapelm
);
1171 pageind
= ((((uintptr_t)mapelm
- (uintptr_t)chunk
->map
) /
1172 sizeof(arena_chunk_map_t
))) + map_bias
;
1173 run
= (arena_run_t
*)((uintptr_t)chunk
+ (uintptr_t)((pageind
-
1174 arena_mapbits_small_runind_get(chunk
, pageind
)) <<
1183 arena_bin_runs_insert(arena_bin_t
*bin
, arena_run_t
*run
)
1185 arena_chunk_t
*chunk
= CHUNK_ADDR2BASE(run
);
1186 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
;
1187 arena_chunk_map_t
*mapelm
= arena_mapp_get(chunk
, pageind
);
1189 assert(arena_run_tree_search(&bin
->runs
, mapelm
) == NULL
);
1191 arena_run_tree_insert(&bin
->runs
, mapelm
);
1195 arena_bin_runs_remove(arena_bin_t
*bin
, arena_run_t
*run
)
1197 arena_chunk_t
*chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
1198 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
;
1199 arena_chunk_map_t
*mapelm
= arena_mapp_get(chunk
, pageind
);
1201 assert(arena_run_tree_search(&bin
->runs
, mapelm
) != NULL
);
1203 arena_run_tree_remove(&bin
->runs
, mapelm
);
1206 static arena_run_t
*
1207 arena_bin_nonfull_run_tryget(arena_bin_t
*bin
)
1209 arena_run_t
*run
= arena_bin_runs_first(bin
);
1211 arena_bin_runs_remove(bin
, run
);
1213 bin
->stats
.reruns
++;
1218 static arena_run_t
*
1219 arena_bin_nonfull_run_get(arena_t
*arena
, arena_bin_t
*bin
)
1223 arena_bin_info_t
*bin_info
;
1225 /* Look for a usable run. */
1226 run
= arena_bin_nonfull_run_tryget(bin
);
1229 /* No existing runs have any space available. */
1231 binind
= arena_bin_index(arena
, bin
);
1232 bin_info
= &arena_bin_info
[binind
];
1234 /* Allocate a new run. */
1235 malloc_mutex_unlock(&bin
->lock
);
1236 /******************************/
1237 malloc_mutex_lock(&arena
->lock
);
1238 run
= arena_run_alloc(arena
, bin_info
->run_size
, false, binind
, false);
1240 bitmap_t
*bitmap
= (bitmap_t
*)((uintptr_t)run
+
1241 (uintptr_t)bin_info
->bitmap_offset
);
1243 /* Initialize run internals. */
1244 VALGRIND_MAKE_MEM_UNDEFINED(run
, bin_info
->reg0_offset
-
1245 bin_info
->redzone_size
);
1248 run
->nfree
= bin_info
->nregs
;
1249 bitmap_init(bitmap
, &bin_info
->bitmap_info
);
1251 malloc_mutex_unlock(&arena
->lock
);
1252 /********************************/
1253 malloc_mutex_lock(&bin
->lock
);
1257 bin
->stats
.curruns
++;
1263 * arena_run_alloc() failed, but another thread may have made
1264 * sufficient memory available while this one dropped bin->lock above,
1265 * so search one more time.
1267 run
= arena_bin_nonfull_run_tryget(bin
);
1274 /* Re-fill bin->runcur, then call arena_run_reg_alloc(). */
1276 arena_bin_malloc_hard(arena_t
*arena
, arena_bin_t
*bin
)
1280 arena_bin_info_t
*bin_info
;
1283 binind
= arena_bin_index(arena
, bin
);
1284 bin_info
= &arena_bin_info
[binind
];
1286 run
= arena_bin_nonfull_run_get(arena
, bin
);
1287 if (bin
->runcur
!= NULL
&& bin
->runcur
->nfree
> 0) {
1289 * Another thread updated runcur while this one ran without the
1290 * bin lock in arena_bin_nonfull_run_get().
1292 assert(bin
->runcur
->nfree
> 0);
1293 ret
= arena_run_reg_alloc(bin
->runcur
, bin_info
);
1295 arena_chunk_t
*chunk
;
1298 * arena_run_alloc() may have allocated run, or it may
1299 * have pulled run from the bin's run tree. Therefore
1300 * it is unsafe to make any assumptions about how run
1301 * has previously been used, and arena_bin_lower_run()
1302 * must be called, as if a region were just deallocated
1305 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
1306 if (run
->nfree
== bin_info
->nregs
)
1307 arena_dalloc_bin_run(arena
, chunk
, run
, bin
);
1309 arena_bin_lower_run(arena
, chunk
, run
, bin
);
1319 assert(bin
->runcur
->nfree
> 0);
1321 return (arena_run_reg_alloc(bin
->runcur
, bin_info
));
1325 arena_prof_accum(arena_t
*arena
, uint64_t accumbytes
)
1328 cassert(config_prof
);
1330 if (config_prof
&& prof_interval
!= 0) {
1331 arena
->prof_accumbytes
+= accumbytes
;
1332 if (arena
->prof_accumbytes
>= prof_interval
) {
1334 arena
->prof_accumbytes
-= prof_interval
;
1340 arena_tcache_fill_small(arena_t
*arena
, tcache_bin_t
*tbin
, size_t binind
,
1341 uint64_t prof_accumbytes
)
1348 assert(tbin
->ncached
== 0);
1351 malloc_mutex_lock(&arena
->lock
);
1352 arena_prof_accum(arena
, prof_accumbytes
);
1353 malloc_mutex_unlock(&arena
->lock
);
1355 bin
= &arena
->bins
[binind
];
1356 malloc_mutex_lock(&bin
->lock
);
1357 for (i
= 0, nfill
= (tcache_bin_info
[binind
].ncached_max
>>
1358 tbin
->lg_fill_div
); i
< nfill
; i
++) {
1359 if ((run
= bin
->runcur
) != NULL
&& run
->nfree
> 0)
1360 ptr
= arena_run_reg_alloc(run
, &arena_bin_info
[binind
]);
1362 ptr
= arena_bin_malloc_hard(arena
, bin
);
1365 if (config_fill
&& opt_junk
) {
1366 arena_alloc_junk_small(ptr
, &arena_bin_info
[binind
],
1369 /* Insert such that low regions get used first. */
1370 tbin
->avail
[nfill
- 1 - i
] = ptr
;
1373 bin
->stats
.allocated
+= i
* arena_bin_info
[binind
].reg_size
;
1374 bin
->stats
.nmalloc
+= i
;
1375 bin
->stats
.nrequests
+= tbin
->tstats
.nrequests
;
1376 bin
->stats
.nfills
++;
1377 tbin
->tstats
.nrequests
= 0;
1379 malloc_mutex_unlock(&bin
->lock
);
1384 arena_alloc_junk_small(void *ptr
, arena_bin_info_t
*bin_info
, bool zero
)
1388 size_t redzone_size
= bin_info
->redzone_size
;
1389 memset((void *)((uintptr_t)ptr
- redzone_size
), 0xa5,
1391 memset((void *)((uintptr_t)ptr
+ bin_info
->reg_size
), 0xa5,
1394 memset((void *)((uintptr_t)ptr
- bin_info
->redzone_size
), 0xa5,
1395 bin_info
->reg_interval
);
1400 arena_dalloc_junk_small(void *ptr
, arena_bin_info_t
*bin_info
)
1402 size_t size
= bin_info
->reg_size
;
1403 size_t redzone_size
= bin_info
->redzone_size
;
1407 for (i
= 1; i
<= redzone_size
; i
++) {
1409 if ((byte
= *(uint8_t *)((uintptr_t)ptr
- i
)) != 0xa5) {
1411 malloc_printf("<jemalloc>: Corrupt redzone "
1412 "%zu byte%s before %p (size %zu), byte=%#x\n", i
,
1413 (i
== 1) ? "" : "s", ptr
, size
, byte
);
1416 for (i
= 0; i
< redzone_size
; i
++) {
1418 if ((byte
= *(uint8_t *)((uintptr_t)ptr
+ size
+ i
)) != 0xa5) {
1420 malloc_printf("<jemalloc>: Corrupt redzone "
1421 "%zu byte%s after end of %p (size %zu), byte=%#x\n",
1422 i
, (i
== 1) ? "" : "s", ptr
, size
, byte
);
1425 if (opt_abort
&& error
)
1428 memset((void *)((uintptr_t)ptr
- redzone_size
), 0x5a,
1429 bin_info
->reg_interval
);
1433 arena_malloc_small(arena_t
*arena
, size_t size
, bool zero
)
1440 binind
= SMALL_SIZE2BIN(size
);
1441 assert(binind
< NBINS
);
1442 bin
= &arena
->bins
[binind
];
1443 size
= arena_bin_info
[binind
].reg_size
;
1445 malloc_mutex_lock(&bin
->lock
);
1446 if ((run
= bin
->runcur
) != NULL
&& run
->nfree
> 0)
1447 ret
= arena_run_reg_alloc(run
, &arena_bin_info
[binind
]);
1449 ret
= arena_bin_malloc_hard(arena
, bin
);
1452 malloc_mutex_unlock(&bin
->lock
);
1457 bin
->stats
.allocated
+= size
;
1458 bin
->stats
.nmalloc
++;
1459 bin
->stats
.nrequests
++;
1461 malloc_mutex_unlock(&bin
->lock
);
1462 if (config_prof
&& isthreaded
== false) {
1463 malloc_mutex_lock(&arena
->lock
);
1464 arena_prof_accum(arena
, size
);
1465 malloc_mutex_unlock(&arena
->lock
);
1468 if (zero
== false) {
1471 arena_alloc_junk_small(ret
,
1472 &arena_bin_info
[binind
], false);
1473 } else if (opt_zero
)
1474 memset(ret
, 0, size
);
1477 if (config_fill
&& opt_junk
) {
1478 arena_alloc_junk_small(ret
, &arena_bin_info
[binind
],
1481 VALGRIND_MAKE_MEM_UNDEFINED(ret
, size
);
1482 memset(ret
, 0, size
);
1489 arena_malloc_large(arena_t
*arena
, size_t size
, bool zero
)
1493 /* Large allocation. */
1494 size
= PAGE_CEILING(size
);
1495 malloc_mutex_lock(&arena
->lock
);
1496 ret
= (void *)arena_run_alloc(arena
, size
, true, BININD_INVALID
, zero
);
1498 malloc_mutex_unlock(&arena
->lock
);
1502 arena
->stats
.nmalloc_large
++;
1503 arena
->stats
.nrequests_large
++;
1504 arena
->stats
.allocated_large
+= size
;
1505 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nmalloc
++;
1506 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nrequests
++;
1507 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].curruns
++;
1510 arena_prof_accum(arena
, size
);
1511 malloc_mutex_unlock(&arena
->lock
);
1513 if (zero
== false) {
1516 memset(ret
, 0xa5, size
);
1518 memset(ret
, 0, size
);
1525 /* Only handles large allocations that require more than page alignment. */
1527 arena_palloc(arena_t
*arena
, size_t size
, size_t alignment
, bool zero
)
1530 size_t alloc_size
, leadsize
, trailsize
;
1532 arena_chunk_t
*chunk
;
1534 assert((size
& PAGE_MASK
) == 0);
1536 alignment
= PAGE_CEILING(alignment
);
1537 alloc_size
= size
+ alignment
- PAGE
;
1539 malloc_mutex_lock(&arena
->lock
);
1540 run
= arena_run_alloc(arena
, alloc_size
, true, BININD_INVALID
, zero
);
1542 malloc_mutex_unlock(&arena
->lock
);
1545 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
1547 leadsize
= ALIGNMENT_CEILING((uintptr_t)run
, alignment
) -
1549 assert(alloc_size
>= leadsize
+ size
);
1550 trailsize
= alloc_size
- leadsize
- size
;
1551 ret
= (void *)((uintptr_t)run
+ leadsize
);
1552 if (leadsize
!= 0) {
1553 arena_run_trim_head(arena
, chunk
, run
, alloc_size
, alloc_size
-
1556 if (trailsize
!= 0) {
1557 arena_run_trim_tail(arena
, chunk
, ret
, size
+ trailsize
, size
,
1562 arena
->stats
.nmalloc_large
++;
1563 arena
->stats
.nrequests_large
++;
1564 arena
->stats
.allocated_large
+= size
;
1565 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nmalloc
++;
1566 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nrequests
++;
1567 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].curruns
++;
1569 malloc_mutex_unlock(&arena
->lock
);
1571 if (config_fill
&& zero
== false) {
1573 memset(ret
, 0xa5, size
);
1575 memset(ret
, 0, size
);
1581 arena_prof_promoted(const void *ptr
, size_t size
)
1583 arena_chunk_t
*chunk
;
1584 size_t pageind
, binind
;
1586 cassert(config_prof
);
1587 assert(ptr
!= NULL
);
1588 assert(CHUNK_ADDR2BASE(ptr
) != ptr
);
1589 assert(isalloc(ptr
, false) == PAGE
);
1590 assert(isalloc(ptr
, true) == PAGE
);
1591 assert(size
<= SMALL_MAXCLASS
);
1593 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
1594 pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> LG_PAGE
;
1595 binind
= SMALL_SIZE2BIN(size
);
1596 assert(binind
< NBINS
);
1597 arena_mapbits_large_binind_set(chunk
, pageind
, binind
);
1599 assert(isalloc(ptr
, false) == PAGE
);
1600 assert(isalloc(ptr
, true) == size
);
1604 arena_dissociate_bin_run(arena_chunk_t
*chunk
, arena_run_t
*run
,
1608 /* Dissociate run from bin. */
1609 if (run
== bin
->runcur
)
1612 size_t binind
= arena_bin_index(chunk
->arena
, bin
);
1613 arena_bin_info_t
*bin_info
= &arena_bin_info
[binind
];
1615 if (bin_info
->nregs
!= 1) {
1617 * This block's conditional is necessary because if the
1618 * run only contains one region, then it never gets
1619 * inserted into the non-full runs tree.
1621 arena_bin_runs_remove(bin
, run
);
1627 arena_dalloc_bin_run(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
1631 arena_bin_info_t
*bin_info
;
1632 size_t npages
, run_ind
, past
;
1634 assert(run
!= bin
->runcur
);
1635 assert(arena_run_tree_search(&bin
->runs
,
1636 arena_mapp_get(chunk
, ((uintptr_t)run
-(uintptr_t)chunk
)>>LG_PAGE
))
1639 binind
= arena_bin_index(chunk
->arena
, run
->bin
);
1640 bin_info
= &arena_bin_info
[binind
];
1642 malloc_mutex_unlock(&bin
->lock
);
1643 /******************************/
1644 npages
= bin_info
->run_size
>> LG_PAGE
;
1645 run_ind
= (size_t)(((uintptr_t)run
- (uintptr_t)chunk
) >> LG_PAGE
);
1646 past
= (size_t)(PAGE_CEILING((uintptr_t)run
+
1647 (uintptr_t)bin_info
->reg0_offset
+ (uintptr_t)(run
->nextind
*
1648 bin_info
->reg_interval
- bin_info
->redzone_size
) -
1649 (uintptr_t)chunk
) >> LG_PAGE
);
1650 malloc_mutex_lock(&arena
->lock
);
1653 * If the run was originally clean, and some pages were never touched,
1654 * trim the clean pages before deallocating the dirty portion of the
1657 assert(arena_mapbits_dirty_get(chunk
, run_ind
) ==
1658 arena_mapbits_dirty_get(chunk
, run_ind
+npages
-1));
1659 if (arena_mapbits_dirty_get(chunk
, run_ind
) == 0 && past
- run_ind
<
1661 /* Trim clean pages. Convert to large run beforehand. */
1663 arena_mapbits_large_set(chunk
, run_ind
, bin_info
->run_size
, 0);
1664 arena_mapbits_large_set(chunk
, run_ind
+npages
-1, 0, 0);
1665 arena_run_trim_tail(arena
, chunk
, run
, (npages
<< LG_PAGE
),
1666 ((past
- run_ind
) << LG_PAGE
), false);
1667 /* npages = past - run_ind; */
1669 arena_run_dalloc(arena
, run
, true, false);
1670 malloc_mutex_unlock(&arena
->lock
);
1671 /****************************/
1672 malloc_mutex_lock(&bin
->lock
);
1674 bin
->stats
.curruns
--;
1678 arena_bin_lower_run(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
1683 * Make sure that if bin->runcur is non-NULL, it refers to the lowest
1684 * non-full run. It is okay to NULL runcur out rather than proactively
1685 * keeping it pointing at the lowest non-full run.
1687 if ((uintptr_t)run
< (uintptr_t)bin
->runcur
) {
1688 /* Switch runcur. */
1689 if (bin
->runcur
->nfree
> 0)
1690 arena_bin_runs_insert(bin
, bin
->runcur
);
1693 bin
->stats
.reruns
++;
1695 arena_bin_runs_insert(bin
, run
);
1699 arena_dalloc_bin_locked(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
1700 arena_chunk_map_t
*mapelm
)
1705 arena_bin_info_t
*bin_info
;
1706 size_t size
, binind
;
1708 pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> LG_PAGE
;
1709 run
= (arena_run_t
*)((uintptr_t)chunk
+ (uintptr_t)((pageind
-
1710 arena_mapbits_small_runind_get(chunk
, pageind
)) << LG_PAGE
));
1712 binind
= arena_ptr_small_binind_get(ptr
, mapelm
->bits
);
1713 bin_info
= &arena_bin_info
[binind
];
1714 if (config_fill
|| config_stats
)
1715 size
= bin_info
->reg_size
;
1717 if (config_fill
&& opt_junk
)
1718 arena_dalloc_junk_small(ptr
, bin_info
);
1720 arena_run_reg_dalloc(run
, ptr
);
1721 if (run
->nfree
== bin_info
->nregs
) {
1722 arena_dissociate_bin_run(chunk
, run
, bin
);
1723 arena_dalloc_bin_run(arena
, chunk
, run
, bin
);
1724 } else if (run
->nfree
== 1 && run
!= bin
->runcur
)
1725 arena_bin_lower_run(arena
, chunk
, run
, bin
);
1728 bin
->stats
.allocated
-= size
;
1729 bin
->stats
.ndalloc
++;
1734 arena_dalloc_bin(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
1735 size_t pageind
, arena_chunk_map_t
*mapelm
)
1740 run
= (arena_run_t
*)((uintptr_t)chunk
+ (uintptr_t)((pageind
-
1741 arena_mapbits_small_runind_get(chunk
, pageind
)) << LG_PAGE
));
1743 malloc_mutex_lock(&bin
->lock
);
1744 arena_dalloc_bin_locked(arena
, chunk
, ptr
, mapelm
);
1745 malloc_mutex_unlock(&bin
->lock
);
1749 arena_dalloc_small(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
1752 arena_chunk_map_t
*mapelm
;
1755 /* arena_ptr_small_binind_get() does extra sanity checking. */
1756 assert(arena_ptr_small_binind_get(ptr
, arena_mapbits_get(chunk
,
1757 pageind
)) != BININD_INVALID
);
1759 mapelm
= arena_mapp_get(chunk
, pageind
);
1760 arena_dalloc_bin(arena
, chunk
, ptr
, pageind
, mapelm
);
1764 arena_dalloc_large_locked(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
)
1767 if (config_fill
|| config_stats
) {
1768 size_t pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> LG_PAGE
;
1769 size_t size
= arena_mapbits_large_size_get(chunk
, pageind
);
1771 if (config_fill
&& config_stats
&& opt_junk
)
1772 memset(ptr
, 0x5a, size
);
1774 arena
->stats
.ndalloc_large
++;
1775 arena
->stats
.allocated_large
-= size
;
1776 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].ndalloc
++;
1777 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].curruns
--;
1781 arena_run_dalloc(arena
, (arena_run_t
*)ptr
, true, false);
1785 arena_dalloc_large(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
)
1788 malloc_mutex_lock(&arena
->lock
);
1789 arena_dalloc_large_locked(arena
, chunk
, ptr
);
1790 malloc_mutex_unlock(&arena
->lock
);
1794 arena_ralloc_large_shrink(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
1795 size_t oldsize
, size_t size
)
1798 assert(size
< oldsize
);
1801 * Shrink the run, and make trailing pages available for other
1804 malloc_mutex_lock(&arena
->lock
);
1805 arena_run_trim_tail(arena
, chunk
, (arena_run_t
*)ptr
, oldsize
, size
,
1808 arena
->stats
.ndalloc_large
++;
1809 arena
->stats
.allocated_large
-= oldsize
;
1810 arena
->stats
.lstats
[(oldsize
>> LG_PAGE
) - 1].ndalloc
++;
1811 arena
->stats
.lstats
[(oldsize
>> LG_PAGE
) - 1].curruns
--;
1813 arena
->stats
.nmalloc_large
++;
1814 arena
->stats
.nrequests_large
++;
1815 arena
->stats
.allocated_large
+= size
;
1816 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nmalloc
++;
1817 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nrequests
++;
1818 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].curruns
++;
1820 malloc_mutex_unlock(&arena
->lock
);
1824 arena_ralloc_large_grow(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
1825 size_t oldsize
, size_t size
, size_t extra
, bool zero
)
1827 size_t pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> LG_PAGE
;
1828 size_t npages
= oldsize
>> LG_PAGE
;
1831 assert(oldsize
== arena_mapbits_large_size_get(chunk
, pageind
));
1833 /* Try to extend the run. */
1834 assert(size
+ extra
> oldsize
);
1835 malloc_mutex_lock(&arena
->lock
);
1836 if (pageind
+ npages
< chunk_npages
&&
1837 arena_mapbits_allocated_get(chunk
, pageind
+npages
) == 0 &&
1838 (followsize
= arena_mapbits_unallocated_size_get(chunk
,
1839 pageind
+npages
)) >= size
- oldsize
) {
1841 * The next run is available and sufficiently large. Split the
1842 * following run, then merge the first part with the existing
1846 size_t splitsize
= (oldsize
+ followsize
<= size
+ extra
)
1847 ? followsize
: size
+ extra
- oldsize
;
1848 arena_run_split(arena
, (arena_run_t
*)((uintptr_t)chunk
+
1849 ((pageind
+npages
) << LG_PAGE
)), splitsize
, true,
1850 BININD_INVALID
, zero
);
1852 size
= oldsize
+ splitsize
;
1853 npages
= size
>> LG_PAGE
;
1856 * Mark the extended run as dirty if either portion of the run
1857 * was dirty before allocation. This is rather pedantic,
1858 * because there's not actually any sequence of events that
1859 * could cause the resulting run to be passed to
1860 * arena_run_dalloc() with the dirty argument set to false
1861 * (which is when dirty flag consistency would really matter).
1863 flag_dirty
= arena_mapbits_dirty_get(chunk
, pageind
) |
1864 arena_mapbits_dirty_get(chunk
, pageind
+npages
-1);
1865 arena_mapbits_large_set(chunk
, pageind
, size
, flag_dirty
);
1866 arena_mapbits_large_set(chunk
, pageind
+npages
-1, 0, flag_dirty
);
1869 arena
->stats
.ndalloc_large
++;
1870 arena
->stats
.allocated_large
-= oldsize
;
1871 arena
->stats
.lstats
[(oldsize
>> LG_PAGE
) - 1].ndalloc
++;
1872 arena
->stats
.lstats
[(oldsize
>> LG_PAGE
) - 1].curruns
--;
1874 arena
->stats
.nmalloc_large
++;
1875 arena
->stats
.nrequests_large
++;
1876 arena
->stats
.allocated_large
+= size
;
1877 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nmalloc
++;
1878 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].nrequests
++;
1879 arena
->stats
.lstats
[(size
>> LG_PAGE
) - 1].curruns
++;
1881 malloc_mutex_unlock(&arena
->lock
);
1884 malloc_mutex_unlock(&arena
->lock
);
1890 * Try to resize a large allocation, in order to avoid copying. This will
1891 * always fail if growing an object, and the following run is already in use.
1894 arena_ralloc_large(void *ptr
, size_t oldsize
, size_t size
, size_t extra
,
1899 psize
= PAGE_CEILING(size
+ extra
);
1900 if (psize
== oldsize
) {
1901 /* Same size class. */
1902 if (config_fill
&& opt_junk
&& size
< oldsize
) {
1903 memset((void *)((uintptr_t)ptr
+ size
), 0x5a, oldsize
-
1908 arena_chunk_t
*chunk
;
1911 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
1912 arena
= chunk
->arena
;
1914 if (psize
< oldsize
) {
1915 /* Fill before shrinking in order avoid a race. */
1916 if (config_fill
&& opt_junk
) {
1917 memset((void *)((uintptr_t)ptr
+ size
), 0x5a,
1920 arena_ralloc_large_shrink(arena
, chunk
, ptr
, oldsize
,
1924 bool ret
= arena_ralloc_large_grow(arena
, chunk
, ptr
,
1925 oldsize
, PAGE_CEILING(size
),
1926 psize
- PAGE_CEILING(size
), zero
);
1927 if (config_fill
&& ret
== false && zero
== false &&
1929 memset((void *)((uintptr_t)ptr
+ oldsize
), 0,
1938 arena_ralloc_no_move(void *ptr
, size_t oldsize
, size_t size
, size_t extra
,
1943 * Avoid moving the allocation if the size class can be left the same.
1945 if (oldsize
<= arena_maxclass
) {
1946 if (oldsize
<= SMALL_MAXCLASS
) {
1947 assert(arena_bin_info
[SMALL_SIZE2BIN(oldsize
)].reg_size
1949 if ((size
+ extra
<= SMALL_MAXCLASS
&&
1950 SMALL_SIZE2BIN(size
+ extra
) ==
1951 SMALL_SIZE2BIN(oldsize
)) || (size
<= oldsize
&&
1952 size
+ extra
>= oldsize
)) {
1953 if (config_fill
&& opt_junk
&& size
< oldsize
) {
1954 memset((void *)((uintptr_t)ptr
+ size
),
1955 0x5a, oldsize
- size
);
1960 assert(size
<= arena_maxclass
);
1961 if (size
+ extra
> SMALL_MAXCLASS
) {
1962 if (arena_ralloc_large(ptr
, oldsize
, size
,
1963 extra
, zero
) == false)
1969 /* Reallocation would require a move. */
1974 arena_ralloc(arena_t
*arena
, void *ptr
, size_t oldsize
, size_t size
,
1975 size_t extra
, size_t alignment
, bool zero
, bool try_tcache_alloc
,
1976 bool try_tcache_dalloc
)
1981 /* Try to avoid moving the allocation. */
1982 ret
= arena_ralloc_no_move(ptr
, oldsize
, size
, extra
, zero
);
1987 * size and oldsize are different enough that we need to move the
1988 * object. In that case, fall back to allocating new space and
1991 if (alignment
!= 0) {
1992 size_t usize
= sa2u(size
+ extra
, alignment
);
1995 ret
= ipallocx(usize
, alignment
, zero
, try_tcache_alloc
, arena
);
1997 ret
= arena_malloc(arena
, size
+ extra
, zero
, try_tcache_alloc
);
2002 /* Try again, this time without extra. */
2003 if (alignment
!= 0) {
2004 size_t usize
= sa2u(size
, alignment
);
2007 ret
= ipallocx(usize
, alignment
, zero
, try_tcache_alloc
,
2010 ret
= arena_malloc(arena
, size
, zero
, try_tcache_alloc
);
2016 /* Junk/zero-filling were already done by ipalloc()/arena_malloc(). */
2019 * Copy at most size bytes (not size+extra), since the caller has no
2020 * expectation that the extra bytes will be reliably preserved.
2022 copysize
= (size
< oldsize
) ? size
: oldsize
;
2023 VALGRIND_MAKE_MEM_UNDEFINED(ret
, copysize
);
2024 memcpy(ret
, ptr
, copysize
);
2025 iqallocx(ptr
, try_tcache_dalloc
);
2030 arena_dss_prec_get(arena_t
*arena
)
2034 malloc_mutex_lock(&arena
->lock
);
2035 ret
= arena
->dss_prec
;
2036 malloc_mutex_unlock(&arena
->lock
);
2041 arena_dss_prec_set(arena_t
*arena
, dss_prec_t dss_prec
)
2044 malloc_mutex_lock(&arena
->lock
);
2045 arena
->dss_prec
= dss_prec
;
2046 malloc_mutex_unlock(&arena
->lock
);
2050 arena_stats_merge(arena_t
*arena
, const char **dss
, size_t *nactive
,
2051 size_t *ndirty
, arena_stats_t
*astats
, malloc_bin_stats_t
*bstats
,
2052 malloc_large_stats_t
*lstats
)
2056 malloc_mutex_lock(&arena
->lock
);
2057 *dss
= dss_prec_names
[arena
->dss_prec
];
2058 *nactive
+= arena
->nactive
;
2059 *ndirty
+= arena
->ndirty
;
2061 astats
->mapped
+= arena
->stats
.mapped
;
2062 astats
->npurge
+= arena
->stats
.npurge
;
2063 astats
->nmadvise
+= arena
->stats
.nmadvise
;
2064 astats
->purged
+= arena
->stats
.purged
;
2065 astats
->allocated_large
+= arena
->stats
.allocated_large
;
2066 astats
->nmalloc_large
+= arena
->stats
.nmalloc_large
;
2067 astats
->ndalloc_large
+= arena
->stats
.ndalloc_large
;
2068 astats
->nrequests_large
+= arena
->stats
.nrequests_large
;
2070 for (i
= 0; i
< nlclasses
; i
++) {
2071 lstats
[i
].nmalloc
+= arena
->stats
.lstats
[i
].nmalloc
;
2072 lstats
[i
].ndalloc
+= arena
->stats
.lstats
[i
].ndalloc
;
2073 lstats
[i
].nrequests
+= arena
->stats
.lstats
[i
].nrequests
;
2074 lstats
[i
].curruns
+= arena
->stats
.lstats
[i
].curruns
;
2076 malloc_mutex_unlock(&arena
->lock
);
2078 for (i
= 0; i
< NBINS
; i
++) {
2079 arena_bin_t
*bin
= &arena
->bins
[i
];
2081 malloc_mutex_lock(&bin
->lock
);
2082 bstats
[i
].allocated
+= bin
->stats
.allocated
;
2083 bstats
[i
].nmalloc
+= bin
->stats
.nmalloc
;
2084 bstats
[i
].ndalloc
+= bin
->stats
.ndalloc
;
2085 bstats
[i
].nrequests
+= bin
->stats
.nrequests
;
2086 if (config_tcache
) {
2087 bstats
[i
].nfills
+= bin
->stats
.nfills
;
2088 bstats
[i
].nflushes
+= bin
->stats
.nflushes
;
2090 bstats
[i
].nruns
+= bin
->stats
.nruns
;
2091 bstats
[i
].reruns
+= bin
->stats
.reruns
;
2092 bstats
[i
].curruns
+= bin
->stats
.curruns
;
2093 malloc_mutex_unlock(&bin
->lock
);
2098 arena_new(arena_t
*arena
, unsigned ind
)
2104 arena
->nthreads
= 0;
2106 if (malloc_mutex_init(&arena
->lock
))
2110 memset(&arena
->stats
, 0, sizeof(arena_stats_t
));
2111 arena
->stats
.lstats
=
2112 (malloc_large_stats_t
*)base_alloc(nlclasses
*
2113 sizeof(malloc_large_stats_t
));
2114 if (arena
->stats
.lstats
== NULL
)
2116 memset(arena
->stats
.lstats
, 0, nlclasses
*
2117 sizeof(malloc_large_stats_t
));
2119 ql_new(&arena
->tcache_ql
);
2123 arena
->prof_accumbytes
= 0;
2125 arena
->dss_prec
= chunk_dss_prec_get();
2127 /* Initialize chunks. */
2128 arena_chunk_dirty_new(&arena
->chunks_dirty
);
2129 arena
->spare
= NULL
;
2133 arena
->npurgatory
= 0;
2135 arena_avail_tree_new(&arena
->runs_avail
);
2137 /* Initialize bins. */
2138 for (i
= 0; i
< NBINS
; i
++) {
2139 bin
= &arena
->bins
[i
];
2140 if (malloc_mutex_init(&bin
->lock
))
2143 arena_run_tree_new(&bin
->runs
);
2145 memset(&bin
->stats
, 0, sizeof(malloc_bin_stats_t
));
2152 * Calculate bin_info->run_size such that it meets the following constraints:
2154 * *) bin_info->run_size >= min_run_size
2155 * *) bin_info->run_size <= arena_maxclass
2156 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
2157 * *) bin_info->nregs <= RUN_MAXREGS
2159 * bin_info->nregs, bin_info->bitmap_offset, and bin_info->reg0_offset are also
2160 * calculated here, since these settings are all interdependent.
2163 bin_info_run_size_calc(arena_bin_info_t
*bin_info
, size_t min_run_size
)
2166 size_t try_run_size
, good_run_size
;
2167 uint32_t try_nregs
, good_nregs
;
2168 uint32_t try_hdr_size
, good_hdr_size
;
2169 uint32_t try_bitmap_offset
, good_bitmap_offset
;
2170 uint32_t try_ctx0_offset
, good_ctx0_offset
;
2171 uint32_t try_redzone0_offset
, good_redzone0_offset
;
2173 assert(min_run_size
>= PAGE
);
2174 assert(min_run_size
<= arena_maxclass
);
2177 * Determine redzone size based on minimum alignment and minimum
2178 * redzone size. Add padding to the end of the run if it is needed to
2179 * align the regions. The padding allows each redzone to be half the
2180 * minimum alignment; without the padding, each redzone would have to
2181 * be twice as large in order to maintain alignment.
2183 if (config_fill
&& opt_redzone
) {
2184 size_t align_min
= ZU(1) << (ffs(bin_info
->reg_size
) - 1);
2185 if (align_min
<= REDZONE_MINSIZE
) {
2186 bin_info
->redzone_size
= REDZONE_MINSIZE
;
2189 bin_info
->redzone_size
= align_min
>> 1;
2190 pad_size
= bin_info
->redzone_size
;
2193 bin_info
->redzone_size
= 0;
2196 bin_info
->reg_interval
= bin_info
->reg_size
+
2197 (bin_info
->redzone_size
<< 1);
2200 * Calculate known-valid settings before entering the run_size
2201 * expansion loop, so that the first part of the loop always copies
2204 * The do..while loop iteratively reduces the number of regions until
2205 * the run header and the regions no longer overlap. A closed formula
2206 * would be quite messy, since there is an interdependency between the
2207 * header's mask length and the number of regions.
2209 try_run_size
= min_run_size
;
2210 try_nregs
= ((try_run_size
- sizeof(arena_run_t
)) /
2211 bin_info
->reg_interval
)
2212 + 1; /* Counter-act try_nregs-- in loop. */
2213 if (try_nregs
> RUN_MAXREGS
) {
2214 try_nregs
= RUN_MAXREGS
2215 + 1; /* Counter-act try_nregs-- in loop. */
2219 try_hdr_size
= sizeof(arena_run_t
);
2220 /* Pad to a long boundary. */
2221 try_hdr_size
= LONG_CEILING(try_hdr_size
);
2222 try_bitmap_offset
= try_hdr_size
;
2223 /* Add space for bitmap. */
2224 try_hdr_size
+= bitmap_size(try_nregs
);
2225 if (config_prof
&& opt_prof
&& prof_promote
== false) {
2226 /* Pad to a quantum boundary. */
2227 try_hdr_size
= QUANTUM_CEILING(try_hdr_size
);
2228 try_ctx0_offset
= try_hdr_size
;
2229 /* Add space for one (prof_ctx_t *) per region. */
2230 try_hdr_size
+= try_nregs
* sizeof(prof_ctx_t
*);
2232 try_ctx0_offset
= 0;
2233 try_redzone0_offset
= try_run_size
- (try_nregs
*
2234 bin_info
->reg_interval
) - pad_size
;
2235 } while (try_hdr_size
> try_redzone0_offset
);
2237 /* run_size expansion loop. */
2240 * Copy valid settings before trying more aggressive settings.
2242 good_run_size
= try_run_size
;
2243 good_nregs
= try_nregs
;
2244 good_hdr_size
= try_hdr_size
;
2245 good_bitmap_offset
= try_bitmap_offset
;
2246 good_ctx0_offset
= try_ctx0_offset
;
2247 good_redzone0_offset
= try_redzone0_offset
;
2249 /* Try more aggressive settings. */
2250 try_run_size
+= PAGE
;
2251 try_nregs
= ((try_run_size
- sizeof(arena_run_t
) - pad_size
) /
2252 bin_info
->reg_interval
)
2253 + 1; /* Counter-act try_nregs-- in loop. */
2254 if (try_nregs
> RUN_MAXREGS
) {
2255 try_nregs
= RUN_MAXREGS
2256 + 1; /* Counter-act try_nregs-- in loop. */
2260 try_hdr_size
= sizeof(arena_run_t
);
2261 /* Pad to a long boundary. */
2262 try_hdr_size
= LONG_CEILING(try_hdr_size
);
2263 try_bitmap_offset
= try_hdr_size
;
2264 /* Add space for bitmap. */
2265 try_hdr_size
+= bitmap_size(try_nregs
);
2266 if (config_prof
&& opt_prof
&& prof_promote
== false) {
2267 /* Pad to a quantum boundary. */
2268 try_hdr_size
= QUANTUM_CEILING(try_hdr_size
);
2269 try_ctx0_offset
= try_hdr_size
;
2271 * Add space for one (prof_ctx_t *) per region.
2273 try_hdr_size
+= try_nregs
*
2274 sizeof(prof_ctx_t
*);
2276 try_redzone0_offset
= try_run_size
- (try_nregs
*
2277 bin_info
->reg_interval
) - pad_size
;
2278 } while (try_hdr_size
> try_redzone0_offset
);
2279 } while (try_run_size
<= arena_maxclass
2280 && try_run_size
<= arena_maxclass
2281 && RUN_MAX_OVRHD
* (bin_info
->reg_interval
<< 3) >
2283 && (try_redzone0_offset
<< RUN_BFP
) > RUN_MAX_OVRHD
* try_run_size
2284 && try_nregs
< RUN_MAXREGS
);
2286 assert(good_hdr_size
<= good_redzone0_offset
);
2288 /* Copy final settings. */
2289 bin_info
->run_size
= good_run_size
;
2290 bin_info
->nregs
= good_nregs
;
2291 bin_info
->bitmap_offset
= good_bitmap_offset
;
2292 bin_info
->ctx0_offset
= good_ctx0_offset
;
2293 bin_info
->reg0_offset
= good_redzone0_offset
+ bin_info
->redzone_size
;
2295 assert(bin_info
->reg0_offset
- bin_info
->redzone_size
+ (bin_info
->nregs
2296 * bin_info
->reg_interval
) + pad_size
== bin_info
->run_size
);
2298 return (good_run_size
);
2304 arena_bin_info_t
*bin_info
;
2305 size_t prev_run_size
= PAGE
;
2307 #define SIZE_CLASS(bin, delta, size) \
2308 bin_info = &arena_bin_info[bin]; \
2309 bin_info->reg_size = size; \
2310 prev_run_size = bin_info_run_size_calc(bin_info, prev_run_size);\
2311 bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
2323 * Compute the header size such that it is large enough to contain the
2324 * page map. The page map is biased to omit entries for the header
2325 * itself, so some iteration is necessary to compute the map bias.
2327 * 1) Compute safe header_size and map_bias values that include enough
2328 * space for an unbiased page map.
2329 * 2) Refine map_bias based on (1) to omit the header pages in the page
2330 * map. The resulting map_bias may be one too small.
2331 * 3) Refine map_bias based on (2). The result will be >= the result
2332 * from (2), and will always be correct.
2335 for (i
= 0; i
< 3; i
++) {
2336 header_size
= offsetof(arena_chunk_t
, map
) +
2337 (sizeof(arena_chunk_map_t
) * (chunk_npages
-map_bias
));
2338 map_bias
= (header_size
>> LG_PAGE
) + ((header_size
& PAGE_MASK
)
2341 assert(map_bias
> 0);
2343 arena_maxclass
= chunksize
- (map_bias
<< LG_PAGE
);
2349 arena_prefork(arena_t
*arena
)
2353 malloc_mutex_prefork(&arena
->lock
);
2354 for (i
= 0; i
< NBINS
; i
++)
2355 malloc_mutex_prefork(&arena
->bins
[i
].lock
);
2359 arena_postfork_parent(arena_t
*arena
)
2363 for (i
= 0; i
< NBINS
; i
++)
2364 malloc_mutex_postfork_parent(&arena
->bins
[i
].lock
);
2365 malloc_mutex_postfork_parent(&arena
->lock
);
2369 arena_postfork_child(arena_t
*arena
)
2373 for (i
= 0; i
< NBINS
; i
++)
2374 malloc_mutex_postfork_child(&arena
->bins
[i
].lock
);
2375 malloc_mutex_postfork_child(&arena
->lock
);