1 /* -*- Mode: C; tab-width: 8; c-basic-offset: 8 -*- */
2 /* vim:set softtabstop=8 shiftwidth=8: */
4 * Copyright (C) 2006-2008 Jason Evans <jasone@FreeBSD.org>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice(s), this list of conditions and the following disclaimer as
12 * the first lines of this file unmodified other than the possible
13 * addition of one or more copyright notices.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice(s), this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************
33 * This allocator implementation is designed to provide scalable performance
34 * for multi-threaded programs on multi-processor systems. The following
35 * features are included for this purpose:
37 * + Multiple arenas are used if there are multiple CPUs, which reduces lock
38 * contention and cache sloshing.
40 * + Cache line sharing between arenas is avoided for internal data
43 * + Memory is managed in chunks and runs (chunks can be split into runs),
44 * rather than as individual pages. This provides a constant-time
45 * mechanism for associating allocations with particular arenas.
47 * Allocation requests are rounded up to the nearest size class, and no record
48 * of the original request size is maintained. Allocations are broken into
49 * categories according to size class. Assuming runtime defaults, 4 kB pages
50 * and a 16 byte quantum on a 32-bit system, the size classes in each category
53 * |=====================================|
54 * | Category | Subcategory | Size |
55 * |=====================================|
56 * | Small | Tiny | 2 |
59 * | |----------------+---------|
60 * | | Quantum-spaced | 16 |
67 * | |----------------+---------|
68 * | | Sub-page | 1 kB |
70 * |=====================================|
78 * |=====================================|
83 * |=====================================|
85 * A different mechanism is used for each category:
87 * Small : Each size class is segregated into its own set of runs. Each run
88 * maintains a bitmap of which regions are free/allocated.
90 * Large : Each allocation is backed by a dedicated run. Metadata are stored
91 * in the associated arena chunk header maps.
93 * Huge : Each allocation is backed by a dedicated contiguous set of chunks.
94 * Metadata are stored in a separate red-black tree.
96 *******************************************************************************
100 * MALLOC_PRODUCTION disables assertions and statistics gathering. It also
101 * defaults the A and J runtime options to off. These settings are appropriate
102 * for production systems.
104 #ifndef MOZ_MEMORY_DEBUG
105 # define MALLOC_PRODUCTION
109 * Use only one arena by default. Mozilla does not currently make extensive
110 * use of concurrent allocation, so the increased fragmentation associated with
111 * multiple arenas is not warranted.
113 #define MOZ_MEMORY_NARENAS_DEFAULT_ONE
116 * MALLOC_STATS enables statistics calculation, and is required for
121 #ifndef MALLOC_PRODUCTION
123 * MALLOC_DEBUG enables assertions and other sanity checks, and disables
126 # define MALLOC_DEBUG
128 /* Memory filling (junk/zero). */
131 /* Allocation tracing. */
132 # ifndef MOZ_MEMORY_WINDOWS
133 # define MALLOC_UTRACE
136 /* Support optional abort() on OOM. */
137 # define MALLOC_XMALLOC
139 /* Support SYSV semantics. */
144 * MALLOC_VALIDATE causes malloc_usable_size() to perform some pointer
145 * validation. There are many possible errors that validation does not even
148 #define MALLOC_VALIDATE
150 /* Embed no-op macros that support memory allocation tracking via valgrind. */
152 # define MALLOC_VALGRIND
154 #ifdef MALLOC_VALGRIND
155 # include <valgrind/valgrind.h>
157 # define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)
158 # define VALGRIND_FREELIKE_BLOCK(addr, rzB)
162 * MALLOC_BALANCE enables monitoring of arena lock contention and dynamically
163 * re-balances arena load if exponentially averaged contention exceeds a
166 /* #define MALLOC_BALANCE */
168 #if (!defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN))
170 * MALLOC_PAGEFILE causes all mmap()ed memory to be backed by temporary
171 * files, so that if a chunk is mapped, it is guaranteed to be swappable.
172 * This avoids asynchronous OOM failures that are due to VM over-commit.
174 * XXX OS X over-commits, so we should probably use mmap() instead of
175 * vm_allocate(), so that MALLOC_PAGEFILE works.
177 #define MALLOC_PAGEFILE
180 #ifdef MALLOC_PAGEFILE
181 /* Write size when initializing a page file. */
182 # define MALLOC_PAGEFILE_WRITE_SIZE 512
185 #ifdef MOZ_MEMORY_LINUX
186 #define _GNU_SOURCE /* For mremap(2). */
187 #define issetugid() 0
188 #if 0 /* Enable in order to test decommit code on Linux. */
189 # define MALLOC_DECOMMIT
193 #ifndef MOZ_MEMORY_WINCE
194 #include <sys/types.h>
204 #ifdef MOZ_MEMORY_WINDOWS
205 #ifndef MOZ_MEMORY_WINCE
206 #include <cruntime.h>
207 #include <internal.h>
210 #include <cmnintrin.h>
212 #define SIZE_MAX UINT_MAX
216 #pragma warning( disable: 4267 4996 4146 )
220 #define inline __inline
221 #define SIZE_T_MAX SIZE_MAX
222 #define STDERR_FILENO 2
223 #define PATH_MAX MAX_PATH
224 #define vsnprintf _vsnprintf
227 static unsigned long tlsIndex
= 0xffffffff;
231 #ifdef MOZ_MEMORY_WINCE
232 #define _pthread_self() GetCurrentThreadId()
234 #define _pthread_self() __threadid()
236 #define issetugid() 0
238 #ifndef MOZ_MEMORY_WINCE
239 /* use MSVC intrinsics */
240 #pragma intrinsic(_BitScanForward)
241 static __forceinline
int
246 if (_BitScanForward(&i
, x
) != 0)
252 /* Implement getenv without using malloc */
253 static char mozillaMallocOptionsBuf
[64];
255 #define getenv xgetenv
257 getenv(const char *name
)
260 if (GetEnvironmentVariableA(name
, (LPSTR
)&mozillaMallocOptionsBuf
,
261 sizeof(mozillaMallocOptionsBuf
)) > 0)
262 return (mozillaMallocOptionsBuf
);
272 static __forceinline
int
276 return 32 - _CountLeadingZeros((-x
) & x
);
280 typedef unsigned char uint8_t;
281 typedef unsigned uint32_t;
282 typedef unsigned long long uint64_t;
283 typedef unsigned long long uintmax_t;
284 typedef long ssize_t
;
286 #define MALLOC_DECOMMIT
289 #ifndef MOZ_MEMORY_WINDOWS
290 #ifndef MOZ_MEMORY_SOLARIS
291 #include <sys/cdefs.h>
294 # define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
297 __FBSDID("$FreeBSD: head/lib/libc/stdlib/malloc.c 180599 2008-07-18 19:35:44Z jasone $");
298 #include "libc_private.h"
302 #include "spinlock.h"
303 #include "namespace.h"
305 #include <sys/mman.h>
307 # define MADV_FREE MADV_DONTNEED
310 # define MAP_NOSYNC 0
312 #include <sys/param.h>
314 #include <sys/stddef.h>
316 #include <sys/time.h>
317 #include <sys/types.h>
318 #ifndef MOZ_MEMORY_SOLARIS
319 #include <sys/sysctl.h>
323 #include <sys/ktrace.h> /* Must come after several other sys/ includes. */
325 #include <machine/atomic.h>
326 #include <machine/cpufunc.h>
327 #include <machine/vmparam.h>
333 # define SIZE_T_MAX SIZE_MAX
336 #ifdef MOZ_MEMORY_DARWIN
337 #define _pthread_self pthread_self
338 #define _pthread_mutex_init pthread_mutex_init
339 #define _pthread_mutex_trylock pthread_mutex_trylock
340 #define _pthread_mutex_lock pthread_mutex_lock
341 #define _pthread_mutex_unlock pthread_mutex_unlock
350 #ifndef MOZ_MEMORY_DARWIN
355 #ifdef MOZ_MEMORY_DARWIN
356 #include <libkern/OSAtomic.h>
357 #include <mach/mach_error.h>
358 #include <mach/mach_init.h>
359 #include <mach/vm_map.h>
360 #include <malloc/malloc.h>
364 #include "un-namespace.h"
369 #include "jemalloc.h"
372 #define bool jemalloc_bool
374 #ifdef MOZ_MEMORY_DARWIN
375 static const bool __isthreaded
= true;
378 #if defined(MOZ_MEMORY_SOLARIS) && defined(MAP_ALIGN) && !defined(JEMALLOC_NEVER_USES_MAP_ALIGN)
379 #define JEMALLOC_USES_MAP_ALIGN /* Required on Solaris 10. Might improve performance elsewhere. */
382 #if defined(MOZ_MEMORY_WINCE) && !defined(MOZ_MEMORY_WINCE6)
383 #define JEMALLOC_USES_MAP_ALIGN /* Required for Windows CE < 6 */
386 #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
390 #ifdef MOZ_MEMORY_WINDOWS
391 /* MSVC++ does not support C99 variable-length arrays. */
392 # define RB_NO_C99_VARARRAYS
397 /* Disable inlining to make debugging easier. */
405 /* Size of stack-allocated buffer passed to strerror_r(). */
406 #define STRERROR_BUF 64
408 /* Minimum alignment of allocations is 2^QUANTUM_2POW_MIN bytes. */
409 # define QUANTUM_2POW_MIN 4
410 #ifdef MOZ_MEMORY_SIZEOF_PTR_2POW
411 # define SIZEOF_PTR_2POW MOZ_MEMORY_SIZEOF_PTR_2POW
413 # define SIZEOF_PTR_2POW 2
416 #ifndef MOZ_MEMORY_DARWIN
417 static const bool __isthreaded
= true;
423 # define QUANTUM_2POW_MIN 4
424 # define SIZEOF_PTR_2POW 2
425 # define CPU_SPINWAIT __asm__ volatile("pause")
428 # define QUANTUM_2POW_MIN 4
429 # define SIZEOF_PTR_2POW 3
432 # define QUANTUM_2POW_MIN 4
433 # define SIZEOF_PTR_2POW 3
437 # define QUANTUM_2POW_MIN 4
438 # define SIZEOF_PTR_2POW 3
442 # define QUANTUM_2POW_MIN 4
443 # define SIZEOF_PTR_2POW 3
444 # define CPU_SPINWAIT __asm__ volatile("pause")
447 # define QUANTUM_2POW_MIN 3
448 # define SIZEOF_PTR_2POW 2
452 # define QUANTUM_2POW_MIN 3
453 # define SIZEOF_PTR_2POW 2
457 # define QUANTUM_2POW_MIN 4
458 # define SIZEOF_PTR_2POW 2
462 #define SIZEOF_PTR (1U << SIZEOF_PTR_2POW)
464 /* sizeof(int) == (1U << SIZEOF_INT_2POW). */
465 #ifndef SIZEOF_INT_2POW
466 # define SIZEOF_INT_2POW 2
469 /* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */
470 #if (!defined(PIC) && !defined(NO_TLS))
475 /* MALLOC_BALANCE requires TLS. */
476 # ifdef MALLOC_BALANCE
477 # undef MALLOC_BALANCE
482 * Size and alignment of memory chunks that are allocated by the OS's virtual
485 #if defined(MOZ_MEMORY_WINCE) && !defined(MOZ_MEMORY_WINCE6)
486 #define CHUNK_2POW_DEFAULT 21
488 #define CHUNK_2POW_DEFAULT 20
490 /* Maximum number of dirty pages per arena. */
491 #define DIRTY_MAX_DEFAULT (1U << 10)
493 /* Default reserve chunks. */
494 #define RESERVE_MIN_2POW_DEFAULT 1
496 * Default range (in chunks) between reserve_min and reserve_max, in addition
497 * to the mandatory one chunk per arena.
499 #ifdef MALLOC_PAGEFILE
500 # define RESERVE_RANGE_2POW_DEFAULT 5
502 # define RESERVE_RANGE_2POW_DEFAULT 0
506 * Maximum size of L1 cache line. This is used to avoid cache line aliasing,
507 * so over-estimates are okay (up to a point), but under-estimates will
508 * negatively affect performance.
510 #define CACHELINE_2POW 6
511 #define CACHELINE ((size_t)(1U << CACHELINE_2POW))
513 /* Smallest size class to support. */
514 #define TINY_MIN_2POW 1
517 * Maximum size class that is a multiple of the quantum, but not (necessarily)
518 * a power of 2. Above this size, allocations are rounded up to the nearest
521 #define SMALL_MAX_2POW_DEFAULT 9
522 #define SMALL_MAX_DEFAULT (1U << SMALL_MAX_2POW_DEFAULT)
525 * RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized
526 * as small as possible such that this setting is still honored, without
527 * violating other constraints. The goal is to make runs as small as possible
528 * without exceeding a per run external fragmentation threshold.
530 * We use binary fixed point math for overhead computations, where the binary
531 * point is implicitly RUN_BFP bits to the left.
533 * Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
534 * honored for some/all object sizes, since there is one bit of header overhead
535 * per object (plus a constant). This constraint is relaxed (ignored) for runs
536 * that are so small that the per-region overhead is greater than:
538 * (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
541 /* \/ Implicit binary fixed point. */
542 #define RUN_MAX_OVRHD 0x0000003dU
543 #define RUN_MAX_OVRHD_RELAX 0x00001800U
545 /* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */
546 #define RUN_MAX_SMALL_2POW 15
547 #define RUN_MAX_SMALL (1U << RUN_MAX_SMALL_2POW)
550 * Hyper-threaded CPUs may need a special instruction inside spin loops in
551 * order to yield to another virtual CPU. If no such instruction is defined
552 * above, make CPU_SPINWAIT a no-op.
555 # define CPU_SPINWAIT
559 * Adaptive spinning must eventually switch to blocking, in order to avoid the
560 * potential for priority inversion deadlock. Backing off past a certain point
561 * can actually waste time.
563 #define SPIN_LIMIT_2POW 11
566 * Conversion from spinning to blocking is expensive; we use (1U <<
567 * BLOCK_COST_2POW) to estimate how many more times costly blocking is than
568 * worst-case spinning.
570 #define BLOCK_COST_2POW 4
572 #ifdef MALLOC_BALANCE
574 * We use an exponential moving average to track recent lock contention,
575 * where the size of the history window is N, and alpha=2/(N+1).
577 * Due to integer math rounding, very small values here can cause
578 * substantial degradation in accuracy, thus making the moving average decay
579 * faster than it would with precise calculation.
581 # define BALANCE_ALPHA_INV_2POW 9
584 * Threshold value for the exponential moving contention average at which to
585 * re-assign a thread.
587 # define BALANCE_THRESHOLD_DEFAULT (1U << (SPIN_LIMIT_2POW-4))
590 /******************************************************************************/
593 * Mutexes based on spinlocks. We can't use normal pthread spinlocks in all
594 * places, because they require malloc()ed memory, which causes bootstrapping
595 * issues in some cases.
597 #if defined(MOZ_MEMORY_WINDOWS)
598 #define malloc_mutex_t CRITICAL_SECTION
599 #define malloc_spinlock_t CRITICAL_SECTION
600 #elif defined(MOZ_MEMORY_DARWIN)
607 #elif defined(MOZ_MEMORY)
608 typedef pthread_mutex_t malloc_mutex_t
;
609 typedef pthread_mutex_t malloc_spinlock_t
;
611 /* XXX these should #ifdef these for freebsd (and linux?) only */
615 typedef malloc_spinlock_t malloc_mutex_t
;
618 /* Set to true once the allocator has been initialized. */
619 static bool malloc_initialized
= false;
621 #if defined(MOZ_MEMORY_WINDOWS)
622 /* No init lock for Windows. */
623 #elif defined(MOZ_MEMORY_DARWIN)
624 static malloc_mutex_t init_lock
= {OS_SPINLOCK_INIT
};
625 #elif defined(MOZ_MEMORY_LINUX)
626 static malloc_mutex_t init_lock
= PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
;
627 #elif defined(MOZ_MEMORY)
628 static malloc_mutex_t init_lock
= PTHREAD_MUTEX_INITIALIZER
;
630 static malloc_mutex_t init_lock
= {_SPINLOCK_INITIALIZER
};
633 /******************************************************************************/
635 * Statistics data structures.
640 typedef struct malloc_bin_stats_s malloc_bin_stats_t
;
641 struct malloc_bin_stats_s
{
643 * Number of allocation requests that corresponded to the size of this
648 /* Total number of runs created for this bin's size class. */
652 * Total number of runs reused by extracting them from the runs tree for
653 * this bin's size class.
657 /* High-water mark for this bin. */
658 unsigned long highruns
;
660 /* Current number of runs in this bin. */
661 unsigned long curruns
;
664 typedef struct arena_stats_s arena_stats_t
;
665 struct arena_stats_s
{
666 /* Number of bytes currently mapped. */
670 * Total number of purge sweeps, total number of madvise calls made,
671 * and total pages purged in order to keep dirty unused memory under
677 #ifdef MALLOC_DECOMMIT
679 * Total number of decommit/commit operations, and total number of
684 uint64_t decommitted
;
687 /* Per-size-category statistics. */
688 size_t allocated_small
;
689 uint64_t nmalloc_small
;
690 uint64_t ndalloc_small
;
692 size_t allocated_large
;
693 uint64_t nmalloc_large
;
694 uint64_t ndalloc_large
;
696 #ifdef MALLOC_BALANCE
697 /* Number of times this arena reassigned a thread due to contention. */
702 typedef struct chunk_stats_s chunk_stats_t
;
703 struct chunk_stats_s
{
704 /* Number of chunks that were allocated. */
707 /* High-water mark for number of chunks allocated. */
708 unsigned long highchunks
;
711 * Current number of chunks allocated. This value isn't maintained for
712 * any other purpose, so keep track of it in order to be able to set
715 unsigned long curchunks
;
718 #endif /* #ifdef MALLOC_STATS */
720 /******************************************************************************/
722 * Extent data structures.
725 /* Tree of extents. */
726 typedef struct extent_node_s extent_node_t
;
727 struct extent_node_s
{
728 /* Linkage for the size/address-ordered tree. */
729 rb_node(extent_node_t
) link_szad
;
731 /* Linkage for the address-ordered tree. */
732 rb_node(extent_node_t
) link_ad
;
734 /* Pointer to the extent that this tree node is responsible for. */
737 /* Total region size. */
740 typedef rb_tree(extent_node_t
) extent_tree_t
;
742 /******************************************************************************/
744 * Radix tree data structures.
747 #ifdef MALLOC_VALIDATE
749 * Size of each radix tree node (must be a power of 2). This impacts tree
752 # if (SIZEOF_PTR == 4)
753 # define MALLOC_RTREE_NODESIZE (1U << 14)
755 # define MALLOC_RTREE_NODESIZE CACHELINE
758 typedef struct malloc_rtree_s malloc_rtree_t
;
759 struct malloc_rtree_s
{
760 malloc_spinlock_t lock
;
763 unsigned level2bits
[1]; /* Dynamically sized. */
767 /******************************************************************************/
769 * Reserve data structures.
772 /* Callback registration. */
773 typedef struct reserve_reg_s reserve_reg_t
;
774 struct reserve_reg_s
{
775 /* Linkage for list of all registered callbacks. */
776 ql_elm(reserve_reg_t
) link
;
778 /* Callback function pointer. */
781 /* Opaque application data pointer. */
785 * Sequence number of condition notification most recently sent to this
791 /******************************************************************************/
793 * Arena data structures.
796 typedef struct arena_s arena_t
;
797 typedef struct arena_bin_s arena_bin_t
;
799 /* Each element of the chunk map corresponds to one page within the chunk. */
800 typedef struct arena_chunk_map_s arena_chunk_map_t
;
801 struct arena_chunk_map_s
{
803 * Linkage for run trees. There are two disjoint uses:
805 * 1) arena_t's runs_avail tree.
806 * 2) arena_run_t conceptually uses this linkage for in-use non-full
807 * runs, rather than directly embedding linkage.
809 rb_node(arena_chunk_map_t
) link
;
812 * Run address (or size) and various flags are stored together. The bit
813 * layout looks like (assuming 32-bit system):
815 * ???????? ???????? ????---- --ckdzla
817 * ? : Unallocated: Run address for first/last pages, unset for internal
819 * Small: Run address.
820 * Large: Run size for first page, unset for trailing pages.
829 * Following are example bit patterns for the three types of runs.
838 * ssssssss ssssssss ssss---- --c-----
839 * xxxxxxxx xxxxxxxx xxxx---- ----d---
840 * ssssssss ssssssss ssss---- -----z--
843 * rrrrrrrr rrrrrrrr rrrr---- -------a
844 * rrrrrrrr rrrrrrrr rrrr---- -------a
845 * rrrrrrrr rrrrrrrr rrrr---- -------a
848 * ssssssss ssssssss ssss---- ------la
849 * -------- -------- -------- ------la
850 * -------- -------- -------- ------la
853 #ifdef MALLOC_DECOMMIT
854 #define CHUNK_MAP_DECOMMITTED ((size_t)0x20U)
856 #define CHUNK_MAP_KEY ((size_t)0x10U)
857 #define CHUNK_MAP_DIRTY ((size_t)0x08U)
858 #define CHUNK_MAP_ZEROED ((size_t)0x04U)
859 #define CHUNK_MAP_LARGE ((size_t)0x02U)
860 #define CHUNK_MAP_ALLOCATED ((size_t)0x01U)
862 typedef rb_tree(arena_chunk_map_t
) arena_avail_tree_t
;
863 typedef rb_tree(arena_chunk_map_t
) arena_run_tree_t
;
865 /* Arena chunk header. */
866 typedef struct arena_chunk_s arena_chunk_t
;
867 struct arena_chunk_s
{
868 /* Arena that owns the chunk. */
871 /* Linkage for the arena's chunks_dirty tree. */
872 rb_node(arena_chunk_t
) link_dirty
;
874 /* Number of dirty pages. */
877 /* Map of pages within chunk that keeps track of free/large/small. */
878 arena_chunk_map_t map
[1]; /* Dynamically sized. */
880 typedef rb_tree(arena_chunk_t
) arena_chunk_tree_t
;
882 typedef struct arena_run_s arena_run_t
;
886 # define ARENA_RUN_MAGIC 0x384adf93
889 /* Bin this run is associated with. */
892 /* Index of first element that might have a free region. */
893 unsigned regs_minelm
;
895 /* Number of free regions in run. */
898 /* Bitmask of in-use regions (0: in use, 1: free). */
899 unsigned regs_mask
[1]; /* Dynamically sized. */
904 * Current run being used to service allocations of this bin's size
910 * Tree of non-full runs. This tree is used when looking for an
911 * existing run when runcur is no longer usable. We choose the
912 * non-full run that is lowest in memory; this policy tends to keep
913 * objects packed well, and it can also help reduce the number of
914 * almost-empty chunks.
916 arena_run_tree_t runs
;
918 /* Size of regions in a run for this bin's size class. */
921 /* Total size of a run for this bin's size class. */
924 /* Total number of regions in a run for this bin's size class. */
927 /* Number of elements in a run's regs_mask for this bin's size class. */
928 uint32_t regs_mask_nelms
;
930 /* Offset of first region in a run for this bin's size class. */
931 uint32_t reg0_offset
;
934 /* Bin statistics. */
935 malloc_bin_stats_t stats
;
942 # define ARENA_MAGIC 0x947d3d24
945 /* All operations on this arena require that lock be locked. */
947 malloc_spinlock_t lock
;
949 pthread_mutex_t lock
;
957 * Chunk allocation sequence number, used to detect races with other
958 * threads during chunk allocation, and then discard unnecessary chunks.
962 /* Tree of dirty-page-containing chunks this arena manages. */
963 arena_chunk_tree_t chunks_dirty
;
966 * In order to avoid rapid chunk allocation/deallocation when an arena
967 * oscillates right on the cusp of needing a new chunk, cache the most
968 * recently freed chunk. The spare is left in the arena's chunk trees
969 * until it is deleted.
971 * There is one spare chunk per arena, rather than one spare total, in
972 * order to avoid interactions between multiple threads that could make
973 * a single spare inadequate.
975 arena_chunk_t
*spare
;
978 * Current count of pages within unused runs that are potentially
979 * dirty, and for which madvise(... MADV_FREE) has not been called. By
980 * tracking this, we can institute a limit on how much dirty unused
981 * memory is mapped for each arena.
986 * Size/address-ordered tree of this arena's available runs. This tree
987 * is used for first-best-fit run allocation.
989 arena_avail_tree_t runs_avail
;
991 #ifdef MALLOC_BALANCE
993 * The arena load balancing machinery needs to keep track of how much
994 * lock contention there is. This value is exponentially averaged.
1000 * bins is used to store rings of free regions of the following sizes,
1001 * assuming a 16-byte quantum, 4kB pagesize, and default MALLOC_OPTIONS.
1022 arena_bin_t bins
[1]; /* Dynamically sized. */
1025 /******************************************************************************/
1030 /* Number of CPUs. */
1031 static unsigned ncpus
;
1034 static size_t pagesize
;
1035 static size_t pagesize_mask
;
1036 static size_t pagesize_2pow
;
1038 /* Various bin-related settings. */
1039 static size_t bin_maxclass
; /* Max size class for bins. */
1040 static unsigned ntbins
; /* Number of (2^n)-spaced tiny bins. */
1041 static unsigned nqbins
; /* Number of quantum-spaced bins. */
1042 static unsigned nsbins
; /* Number of (2^n)-spaced sub-page bins. */
1043 static size_t small_min
;
1044 static size_t small_max
;
1046 /* Various quantum-related settings. */
1047 static size_t quantum
;
1048 static size_t quantum_mask
; /* (quantum - 1). */
1050 /* Various chunk-related settings. */
1051 static size_t chunksize
;
1052 static size_t chunksize_mask
; /* (chunksize - 1). */
1053 static size_t chunk_npages
;
1054 static size_t arena_chunk_header_npages
;
1055 static size_t arena_maxclass
; /* Max size class for arenas. */
1062 #ifdef MALLOC_VALIDATE
1063 static malloc_rtree_t
*chunk_rtree
;
1066 /* Protects chunk-related data structures. */
1067 static malloc_mutex_t huge_mtx
;
1069 /* Tree of chunks that are stand-alone huge allocations. */
1070 static extent_tree_t huge
;
1073 /* Huge allocation statistics. */
1074 static uint64_t huge_nmalloc
;
1075 static uint64_t huge_ndalloc
;
1076 static size_t huge_allocated
;
1084 #ifdef MALLOC_PAGEFILE
1085 static char pagefile_templ
[PATH_MAX
];
1088 /* Protects reserve-related data structures. */
1089 static malloc_mutex_t reserve_mtx
;
1092 * Bounds on acceptable reserve size, and current reserve size. Reserve
1093 * depletion may cause (reserve_cur < reserve_min).
1095 static size_t reserve_min
;
1096 static size_t reserve_cur
;
1097 static size_t reserve_max
;
1099 /* List of registered callbacks. */
1100 static ql_head(reserve_reg_t
) reserve_regs
;
1103 * Condition notification sequence number, used to determine whether all
1104 * registered callbacks have been notified of the most current condition.
1106 static uint64_t reserve_seq
;
1109 * Trees of chunks currently in the memory reserve. Depending on function,
1110 * different tree orderings are needed, which is why there are two trees with
1111 * the same contents.
1113 static extent_tree_t reserve_chunks_szad
;
1114 static extent_tree_t reserve_chunks_ad
;
1116 /****************************/
1118 * base (internal allocation).
1122 * Current pages that are being used for internal memory allocations. These
1123 * pages are carved up in cacheline-size quanta, so that there is no chance of
1124 * false cache line sharing.
1126 static void *base_pages
;
1127 static void *base_next_addr
;
1128 #ifdef MALLOC_DECOMMIT
1129 static void *base_next_decommitted
;
1131 static void *base_past_addr
; /* Addr immediately past base_pages. */
1132 static extent_node_t
*base_nodes
;
1133 static reserve_reg_t
*base_reserve_regs
;
1134 static malloc_mutex_t base_mtx
;
1136 static size_t base_mapped
;
1145 * Arenas that are used to service external requests. Not all elements of the
1146 * arenas array are necessarily used; arenas are created lazily as needed.
1148 static arena_t
**arenas
;
1149 static unsigned narenas
;
1150 static unsigned narenas_2pow
;
1152 # ifdef MALLOC_BALANCE
1153 static unsigned narenas_2pow
;
1155 static unsigned next_arena
;
1159 static malloc_spinlock_t arenas_lock
; /* Protects arenas initialization. */
1161 static pthread_mutex_t arenas_lock
; /* Protects arenas initialization. */
1166 * Map of pthread_self() --> arenas[???], used for selecting an arena to use
1169 #ifndef MOZ_MEMORY_WINDOWS
1170 static __thread arena_t
*arenas_map
;
1175 /* Chunk statistics. */
1176 static chunk_stats_t stats_chunks
;
1179 /*******************************/
1181 * Runtime configuration options.
1183 const char *_malloc_options
;
1185 #ifndef MALLOC_PRODUCTION
1186 static bool opt_abort
= true;
1188 static bool opt_junk
= true;
1191 static bool opt_abort
= false;
1193 static bool opt_junk
= false;
1196 static size_t opt_dirty_max
= DIRTY_MAX_DEFAULT
;
1197 #ifdef MALLOC_BALANCE
1198 static uint64_t opt_balance_threshold
= BALANCE_THRESHOLD_DEFAULT
;
1200 static bool opt_print_stats
= false;
1201 static size_t opt_quantum_2pow
= QUANTUM_2POW_MIN
;
1202 static size_t opt_small_max_2pow
= SMALL_MAX_2POW_DEFAULT
;
1203 static size_t opt_chunk_2pow
= CHUNK_2POW_DEFAULT
;
1204 static int opt_reserve_min_lshift
= 0;
1205 static int opt_reserve_range_lshift
= 0;
1206 #ifdef MALLOC_PAGEFILE
1207 static bool opt_pagefile
= false;
1209 #ifdef MALLOC_UTRACE
1210 static bool opt_utrace
= false;
1213 static bool opt_sysv
= false;
1215 #ifdef MALLOC_XMALLOC
1216 static bool opt_xmalloc
= false;
1219 static bool opt_zero
= false;
1221 static int opt_narenas_lshift
= 0;
1223 #ifdef MALLOC_UTRACE
1230 #define UTRACE(a, b, c) \
1232 malloc_utrace_t ut; \
1236 utrace(&ut, sizeof(ut)); \
1239 #define UTRACE(a, b, c)
1242 /******************************************************************************/
1244 * Begin function prototypes for non-inline static functions.
1247 static char *umax2s(uintmax_t x
, char *s
);
1248 static bool malloc_mutex_init(malloc_mutex_t
*mutex
);
1249 static bool malloc_spin_init(malloc_spinlock_t
*lock
);
1250 static void wrtmessage(const char *p1
, const char *p2
, const char *p3
,
1253 #ifdef MOZ_MEMORY_DARWIN
1254 /* Avoid namespace collision with OS X's malloc APIs. */
1255 #define malloc_printf moz_malloc_printf
1257 static void malloc_printf(const char *format
, ...);
1259 static bool base_pages_alloc_mmap(size_t minsize
);
1260 static bool base_pages_alloc(size_t minsize
);
1261 static void *base_alloc(size_t size
);
1262 static void *base_calloc(size_t number
, size_t size
);
1263 static extent_node_t
*base_node_alloc(void);
1264 static void base_node_dealloc(extent_node_t
*node
);
1265 static reserve_reg_t
*base_reserve_reg_alloc(void);
1266 static void base_reserve_reg_dealloc(reserve_reg_t
*reg
);
1268 static void stats_print(arena_t
*arena
);
1270 static void *pages_map(void *addr
, size_t size
, int pfd
);
1271 static void pages_unmap(void *addr
, size_t size
);
1272 static void *chunk_alloc_mmap(size_t size
, bool pagefile
);
1273 #ifdef MALLOC_PAGEFILE
1274 static int pagefile_init(size_t size
);
1275 static void pagefile_close(int pfd
);
1277 static void *chunk_recycle_reserve(size_t size
, bool zero
);
1278 static void *chunk_alloc(size_t size
, bool zero
, bool pagefile
);
1279 static extent_node_t
*chunk_dealloc_reserve(void *chunk
, size_t size
);
1280 static void chunk_dealloc_mmap(void *chunk
, size_t size
);
1281 static void chunk_dealloc(void *chunk
, size_t size
);
1283 static arena_t
*choose_arena_hard(void);
1285 static void arena_run_split(arena_t
*arena
, arena_run_t
*run
, size_t size
,
1286 bool large
, bool zero
);
1287 static void arena_chunk_init(arena_t
*arena
, arena_chunk_t
*chunk
);
1288 static void arena_chunk_dealloc(arena_t
*arena
, arena_chunk_t
*chunk
);
1289 static arena_run_t
*arena_run_alloc(arena_t
*arena
, arena_bin_t
*bin
,
1290 size_t size
, bool large
, bool zero
);
1291 static void arena_purge(arena_t
*arena
);
1292 static void arena_run_dalloc(arena_t
*arena
, arena_run_t
*run
, bool dirty
);
1293 static void arena_run_trim_head(arena_t
*arena
, arena_chunk_t
*chunk
,
1294 arena_run_t
*run
, size_t oldsize
, size_t newsize
);
1295 static void arena_run_trim_tail(arena_t
*arena
, arena_chunk_t
*chunk
,
1296 arena_run_t
*run
, size_t oldsize
, size_t newsize
, bool dirty
);
1297 static arena_run_t
*arena_bin_nonfull_run_get(arena_t
*arena
, arena_bin_t
*bin
);
1298 static void *arena_bin_malloc_hard(arena_t
*arena
, arena_bin_t
*bin
);
1299 static size_t arena_bin_run_size_calc(arena_bin_t
*bin
, size_t min_run_size
);
1300 #ifdef MALLOC_BALANCE
1301 static void arena_lock_balance_hard(arena_t
*arena
);
1303 static void *arena_malloc_large(arena_t
*arena
, size_t size
, bool zero
);
1304 static void *arena_palloc(arena_t
*arena
, size_t alignment
, size_t size
,
1306 static size_t arena_salloc(const void *ptr
);
1307 static void arena_dalloc_large(arena_t
*arena
, arena_chunk_t
*chunk
,
1309 static void arena_ralloc_large_shrink(arena_t
*arena
, arena_chunk_t
*chunk
,
1310 void *ptr
, size_t size
, size_t oldsize
);
1311 static bool arena_ralloc_large_grow(arena_t
*arena
, arena_chunk_t
*chunk
,
1312 void *ptr
, size_t size
, size_t oldsize
);
1313 static bool arena_ralloc_large(void *ptr
, size_t size
, size_t oldsize
);
1314 static void *arena_ralloc(void *ptr
, size_t size
, size_t oldsize
);
1315 static bool arena_new(arena_t
*arena
);
1316 static arena_t
*arenas_extend(unsigned ind
);
1317 static void *huge_malloc(size_t size
, bool zero
);
1318 static void *huge_palloc(size_t alignment
, size_t size
);
1319 static void *huge_ralloc(void *ptr
, size_t size
, size_t oldsize
);
1320 static void huge_dalloc(void *ptr
);
1321 static void malloc_print_stats(void);
1322 #ifndef MOZ_MEMORY_WINDOWS
1325 bool malloc_init_hard(void);
1326 static void reserve_shrink(void);
1327 static uint64_t reserve_notify(reserve_cnd_t cnd
, size_t size
, uint64_t seq
);
1328 static uint64_t reserve_crit(size_t size
, const char *fname
, uint64_t seq
);
1329 static void reserve_fail(size_t size
, const char *fname
);
1331 void _malloc_prefork(void);
1332 void _malloc_postfork(void);
1335 * End function prototypes.
1337 /******************************************************************************/
1340 * umax2s() provides minimal integer printing functionality, which is
1341 * especially useful for situations where allocation in vsnprintf() calls would
1342 * potentially cause deadlock.
1344 #define UMAX2S_BUFSIZE 21
1346 umax2s(uintmax_t x
, char *s
)
1350 i
= UMAX2S_BUFSIZE
- 1;
1354 s
[i
] = "0123456789"[x
% 10];
1362 wrtmessage(const char *p1
, const char *p2
, const char *p3
, const char *p4
)
1364 #ifdef MOZ_MEMORY_WINCE
1366 #define WRT_PRINT(s) \
1367 MultiByteToWideChar(CP_ACP, 0, s, -1, buf, 1024); \
1368 OutputDebugStringW(buf)
1375 #if defined(MOZ_MEMORY) && !defined(MOZ_MEMORY_WINDOWS)
1376 #define _write write
1378 _write(STDERR_FILENO
, p1
, (unsigned int) strlen(p1
));
1379 _write(STDERR_FILENO
, p2
, (unsigned int) strlen(p2
));
1380 _write(STDERR_FILENO
, p3
, (unsigned int) strlen(p3
));
1381 _write(STDERR_FILENO
, p4
, (unsigned int) strlen(p4
));
1386 #define _malloc_message malloc_message
1388 void (*_malloc_message
)(const char *p1
, const char *p2
, const char *p3
,
1389 const char *p4
) = wrtmessage
;
1392 # define assert(e) do { \
1394 char line_buf[UMAX2S_BUFSIZE]; \
1395 _malloc_message(__FILE__, ":", umax2s(__LINE__, \
1396 line_buf), ": Failed assertion: "); \
1397 _malloc_message("\"", #e, "\"\n", ""); \
1405 /******************************************************************************/
1407 * Begin mutex. We can't use normal pthread mutexes in all places, because
1408 * they require malloc()ed memory, which causes bootstrapping issues in some
1413 malloc_mutex_init(malloc_mutex_t
*mutex
)
1415 #if defined(MOZ_MEMORY_WINCE)
1416 InitializeCriticalSection(mutex
);
1417 #elif defined(MOZ_MEMORY_WINDOWS)
1419 if (! __crtInitCritSecAndSpinCount(mutex
, _CRT_SPINCOUNT
))
1421 #elif defined(MOZ_MEMORY_DARWIN)
1422 mutex
->lock
= OS_SPINLOCK_INIT
;
1423 #elif defined(MOZ_MEMORY_LINUX)
1424 pthread_mutexattr_t attr
;
1425 if (pthread_mutexattr_init(&attr
) != 0)
1427 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
1428 if (pthread_mutex_init(mutex
, &attr
) != 0) {
1429 pthread_mutexattr_destroy(&attr
);
1432 pthread_mutexattr_destroy(&attr
);
1433 #elif defined(MOZ_MEMORY)
1434 if (pthread_mutex_init(mutex
, NULL
) != 0)
1437 static const spinlock_t lock
= _SPINLOCK_INITIALIZER
;
1445 malloc_mutex_lock(malloc_mutex_t
*mutex
)
1448 #if defined(MOZ_MEMORY_WINDOWS)
1449 EnterCriticalSection(mutex
);
1450 #elif defined(MOZ_MEMORY_DARWIN)
1451 OSSpinLockLock(&mutex
->lock
);
1452 #elif defined(MOZ_MEMORY)
1453 pthread_mutex_lock(mutex
);
1456 _SPINLOCK(&mutex
->lock
);
1461 malloc_mutex_unlock(malloc_mutex_t
*mutex
)
1464 #if defined(MOZ_MEMORY_WINDOWS)
1465 LeaveCriticalSection(mutex
);
1466 #elif defined(MOZ_MEMORY_DARWIN)
1467 OSSpinLockUnlock(&mutex
->lock
);
1468 #elif defined(MOZ_MEMORY)
1469 pthread_mutex_unlock(mutex
);
1472 _SPINUNLOCK(&mutex
->lock
);
1477 malloc_spin_init(malloc_spinlock_t
*lock
)
1479 #if defined(MOZ_MEMORY_WINCE)
1480 InitializeCriticalSection(lock
);
1481 #elif defined(MOZ_MEMORY_WINDOWS)
1483 if (! __crtInitCritSecAndSpinCount(lock
, _CRT_SPINCOUNT
))
1485 #elif defined(MOZ_MEMORY_DARWIN)
1486 lock
->lock
= OS_SPINLOCK_INIT
;
1487 #elif defined(MOZ_MEMORY_LINUX)
1488 pthread_mutexattr_t attr
;
1489 if (pthread_mutexattr_init(&attr
) != 0)
1491 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
1492 if (pthread_mutex_init(lock
, &attr
) != 0) {
1493 pthread_mutexattr_destroy(&attr
);
1496 pthread_mutexattr_destroy(&attr
);
1497 #elif defined(MOZ_MEMORY)
1498 if (pthread_mutex_init(lock
, NULL
) != 0)
1501 lock
->lock
= _SPINLOCK_INITIALIZER
;
1507 malloc_spin_lock(malloc_spinlock_t
*lock
)
1510 #if defined(MOZ_MEMORY_WINDOWS)
1511 EnterCriticalSection(lock
);
1512 #elif defined(MOZ_MEMORY_DARWIN)
1513 OSSpinLockLock(&lock
->lock
);
1514 #elif defined(MOZ_MEMORY)
1515 pthread_mutex_lock(lock
);
1518 _SPINLOCK(&lock
->lock
);
1523 malloc_spin_unlock(malloc_spinlock_t
*lock
)
1525 #if defined(MOZ_MEMORY_WINDOWS)
1526 LeaveCriticalSection(lock
);
1527 #elif defined(MOZ_MEMORY_DARWIN)
1528 OSSpinLockUnlock(&lock
->lock
);
1529 #elif defined(MOZ_MEMORY)
1530 pthread_mutex_unlock(lock
);
1533 _SPINUNLOCK(&lock
->lock
);
1540 /******************************************************************************/
1542 * Begin spin lock. Spin locks here are actually adaptive mutexes that block
1543 * after a period of spinning, because unbounded spinning would allow for
1544 * priority inversion.
1547 #if defined(MOZ_MEMORY) && !defined(MOZ_MEMORY_DARWIN)
1548 # define malloc_spin_init malloc_mutex_init
1549 # define malloc_spin_lock malloc_mutex_lock
1550 # define malloc_spin_unlock malloc_mutex_unlock
1555 * We use an unpublished interface to initialize pthread mutexes with an
1556 * allocation callback, in order to avoid infinite recursion.
1558 int _pthread_mutex_init_calloc_cb(pthread_mutex_t
*mutex
,
1559 void *(calloc_cb
)(size_t, size_t));
1561 __weak_reference(_pthread_mutex_init_calloc_cb_stub
,
1562 _pthread_mutex_init_calloc_cb
);
1565 _pthread_mutex_init_calloc_cb_stub(pthread_mutex_t
*mutex
,
1566 void *(calloc_cb
)(size_t, size_t))
1573 malloc_spin_init(pthread_mutex_t
*lock
)
1576 if (_pthread_mutex_init_calloc_cb(lock
, base_calloc
) != 0)
1582 static inline unsigned
1583 malloc_spin_lock(pthread_mutex_t
*lock
)
1588 if (_pthread_mutex_trylock(lock
) != 0) {
1590 volatile unsigned j
;
1592 /* Exponentially back off. */
1593 for (i
= 1; i
<= SPIN_LIMIT_2POW
; i
++) {
1594 for (j
= 0; j
< (1U << i
); j
++)
1598 if (_pthread_mutex_trylock(lock
) == 0)
1603 * Spinning failed. Block until the lock becomes
1604 * available, in order to avoid indefinite priority
1607 _pthread_mutex_lock(lock
);
1608 assert((ret
<< BLOCK_COST_2POW
) != 0);
1609 return (ret
<< BLOCK_COST_2POW
);
1617 malloc_spin_unlock(pthread_mutex_t
*lock
)
1621 _pthread_mutex_unlock(lock
);
1628 /******************************************************************************/
1630 * Begin Utility functions/macros.
1633 /* Return the chunk address for allocation address a. */
1634 #define CHUNK_ADDR2BASE(a) \
1635 ((void *)((uintptr_t)(a) & ~chunksize_mask))
1637 /* Return the chunk offset of address a. */
1638 #define CHUNK_ADDR2OFFSET(a) \
1639 ((size_t)((uintptr_t)(a) & chunksize_mask))
1641 /* Return the smallest chunk multiple that is >= s. */
1642 #define CHUNK_CEILING(s) \
1643 (((s) + chunksize_mask) & ~chunksize_mask)
1645 /* Return the smallest cacheline multiple that is >= s. */
1646 #define CACHELINE_CEILING(s) \
1647 (((s) + (CACHELINE - 1)) & ~(CACHELINE - 1))
1649 /* Return the smallest quantum multiple that is >= a. */
1650 #define QUANTUM_CEILING(a) \
1651 (((a) + quantum_mask) & ~quantum_mask)
1653 /* Return the smallest pagesize multiple that is >= s. */
1654 #define PAGE_CEILING(s) \
1655 (((s) + pagesize_mask) & ~pagesize_mask)
1657 /* Compute the smallest power of 2 that is >= x. */
1658 static inline size_t
1668 #if (SIZEOF_PTR == 8)
1675 #ifdef MALLOC_BALANCE
1677 * Use a simple linear congruential pseudo-random number generator:
1679 * prn(y) = (a*x + c) % m
1681 * where the following constants ensure maximal period:
1683 * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4.
1684 * c == Odd number (relatively prime to 2^n).
1687 * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints.
1689 * This choice of m has the disadvantage that the quality of the bits is
1690 * proportional to bit position. For example. the lowest bit has a cycle of 2,
1691 * the next has a cycle of 4, etc. For this reason, we prefer to use the upper
1694 # define PRN_DEFINE(suffix, var, a, c) \
1695 static inline void \
1696 sprn_##suffix(uint32_t seed) \
1701 static inline uint32_t \
1702 prn_##suffix(uint32_t lg_range) \
1706 assert(lg_range > 0); \
1707 assert(lg_range <= 32); \
1709 x = (var * (a)) + (c); \
1711 ret = x >> (32 - lg_range); \
1715 # define SPRN(suffix, seed) sprn_##suffix(seed)
1716 # define PRN(suffix, lg_range) prn_##suffix(lg_range)
1719 #ifdef MALLOC_BALANCE
1720 /* Define the PRNG used for arena assignment. */
1721 static __thread
uint32_t balance_x
;
1722 PRN_DEFINE(balance
, balance_x
, 1297, 1301)
1725 #ifdef MALLOC_UTRACE
1727 utrace(const void *addr
, size_t len
)
1729 malloc_utrace_t
*ut
= (malloc_utrace_t
*)addr
;
1731 assert(len
== sizeof(malloc_utrace_t
));
1733 if (ut
->p
== NULL
&& ut
->s
== 0 && ut
->r
== NULL
)
1734 malloc_printf("%d x USER malloc_init()\n", getpid());
1735 else if (ut
->p
== NULL
&& ut
->r
!= NULL
) {
1736 malloc_printf("%d x USER %p = malloc(%zu)\n", getpid(), ut
->r
,
1738 } else if (ut
->p
!= NULL
&& ut
->r
!= NULL
) {
1739 malloc_printf("%d x USER %p = realloc(%p, %zu)\n", getpid(),
1740 ut
->r
, ut
->p
, ut
->s
);
1742 malloc_printf("%d x USER free(%p)\n", getpid(), ut
->p
);
1748 static inline const char *
1752 return ("<jemalloc>");
1757 * Print to stderr in such a way as to (hopefully) avoid memory allocation.
1760 malloc_printf(const char *format
, ...)
1766 va_start(ap
, format
);
1767 vsnprintf(buf
, sizeof(buf
), format
, ap
);
1769 _malloc_message(buf
, "", "", "");
1774 /******************************************************************************/
1776 #ifdef MALLOC_DECOMMIT
1778 pages_decommit(void *addr
, size_t size
)
1781 #ifdef MOZ_MEMORY_WINDOWS
1782 VirtualFree(addr
, size
, MEM_DECOMMIT
);
1784 if (mmap(addr
, size
, PROT_NONE
, MAP_FIXED
| MAP_PRIVATE
| MAP_ANON
, -1,
1791 pages_commit(void *addr
, size_t size
)
1794 # ifdef MOZ_MEMORY_WINDOWS
1795 VirtualAlloc(addr
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1797 if (mmap(addr
, size
, PROT_READ
| PROT_WRITE
, MAP_FIXED
| MAP_PRIVATE
|
1798 MAP_ANON
, -1, 0) == MAP_FAILED
)
1805 base_pages_alloc_mmap(size_t minsize
)
1809 #ifdef MALLOC_DECOMMIT
1814 assert(minsize
!= 0);
1815 csize
= CHUNK_CEILING(minsize
);
1816 #ifdef MALLOC_PAGEFILE
1818 pfd
= pagefile_init(csize
);
1824 base_pages
= pages_map(NULL
, csize
, pfd
);
1825 if (base_pages
== NULL
) {
1829 base_next_addr
= base_pages
;
1830 base_past_addr
= (void *)((uintptr_t)base_pages
+ csize
);
1831 #ifdef MALLOC_DECOMMIT
1833 * Leave enough pages for minsize committed, since otherwise they would
1834 * have to be immediately recommitted.
1836 pminsize
= PAGE_CEILING(minsize
);
1837 base_next_decommitted
= (void *)((uintptr_t)base_pages
+ pminsize
);
1838 if (pminsize
< csize
)
1839 pages_decommit(base_next_decommitted
, csize
- pminsize
);
1842 base_mapped
+= csize
;
1847 #ifdef MALLOC_PAGEFILE
1849 pagefile_close(pfd
);
1855 base_pages_alloc(size_t minsize
)
1858 if (base_pages_alloc_mmap(minsize
) == false)
1865 base_alloc(size_t size
)
1870 /* Round size up to nearest multiple of the cacheline size. */
1871 csize
= CACHELINE_CEILING(size
);
1873 malloc_mutex_lock(&base_mtx
);
1874 /* Make sure there's enough space for the allocation. */
1875 if ((uintptr_t)base_next_addr
+ csize
> (uintptr_t)base_past_addr
) {
1876 if (base_pages_alloc(csize
)) {
1877 malloc_mutex_unlock(&base_mtx
);
1882 ret
= base_next_addr
;
1883 base_next_addr
= (void *)((uintptr_t)base_next_addr
+ csize
);
1884 #ifdef MALLOC_DECOMMIT
1885 /* Make sure enough pages are committed for the new allocation. */
1886 if ((uintptr_t)base_next_addr
> (uintptr_t)base_next_decommitted
) {
1887 void *pbase_next_addr
=
1888 (void *)(PAGE_CEILING((uintptr_t)base_next_addr
));
1890 pages_commit(base_next_decommitted
, (uintptr_t)pbase_next_addr
-
1891 (uintptr_t)base_next_decommitted
);
1892 base_next_decommitted
= pbase_next_addr
;
1895 malloc_mutex_unlock(&base_mtx
);
1896 VALGRIND_MALLOCLIKE_BLOCK(ret
, size
, 0, false);
1902 base_calloc(size_t number
, size_t size
)
1906 ret
= base_alloc(number
* size
);
1907 #ifdef MALLOC_VALGRIND
1909 VALGRIND_FREELIKE_BLOCK(ret
, 0);
1910 VALGRIND_MALLOCLIKE_BLOCK(ret
, size
, 0, true);
1913 memset(ret
, 0, number
* size
);
1918 static extent_node_t
*
1919 base_node_alloc(void)
1923 malloc_mutex_lock(&base_mtx
);
1924 if (base_nodes
!= NULL
) {
1926 base_nodes
= *(extent_node_t
**)ret
;
1927 VALGRIND_FREELIKE_BLOCK(ret
, 0);
1928 VALGRIND_MALLOCLIKE_BLOCK(ret
, sizeof(extent_node_t
), 0, false);
1929 malloc_mutex_unlock(&base_mtx
);
1931 malloc_mutex_unlock(&base_mtx
);
1932 ret
= (extent_node_t
*)base_alloc(sizeof(extent_node_t
));
1939 base_node_dealloc(extent_node_t
*node
)
1942 malloc_mutex_lock(&base_mtx
);
1943 VALGRIND_FREELIKE_BLOCK(node
, 0);
1944 VALGRIND_MALLOCLIKE_BLOCK(node
, sizeof(extent_node_t
*), 0, false);
1945 *(extent_node_t
**)node
= base_nodes
;
1947 malloc_mutex_unlock(&base_mtx
);
1950 static reserve_reg_t
*
1951 base_reserve_reg_alloc(void)
1955 malloc_mutex_lock(&base_mtx
);
1956 if (base_reserve_regs
!= NULL
) {
1957 ret
= base_reserve_regs
;
1958 base_reserve_regs
= *(reserve_reg_t
**)ret
;
1959 VALGRIND_FREELIKE_BLOCK(ret
, 0);
1960 VALGRIND_MALLOCLIKE_BLOCK(ret
, sizeof(reserve_reg_t
), 0, false);
1961 malloc_mutex_unlock(&base_mtx
);
1963 malloc_mutex_unlock(&base_mtx
);
1964 ret
= (reserve_reg_t
*)base_alloc(sizeof(reserve_reg_t
));
1971 base_reserve_reg_dealloc(reserve_reg_t
*reg
)
1974 malloc_mutex_lock(&base_mtx
);
1975 VALGRIND_FREELIKE_BLOCK(reg
, 0);
1976 VALGRIND_MALLOCLIKE_BLOCK(reg
, sizeof(reserve_reg_t
*), 0, false);
1977 *(reserve_reg_t
**)reg
= base_reserve_regs
;
1978 base_reserve_regs
= reg
;
1979 malloc_mutex_unlock(&base_mtx
);
1982 /******************************************************************************/
1986 stats_print(arena_t
*arena
)
1988 unsigned i
, gap_start
;
1990 #ifdef MOZ_MEMORY_WINDOWS
1991 malloc_printf("dirty: %Iu page%s dirty, %I64u sweep%s,"
1992 " %I64u madvise%s, %I64u page%s purged\n",
1993 arena
->ndirty
, arena
->ndirty
== 1 ? "" : "s",
1994 arena
->stats
.npurge
, arena
->stats
.npurge
== 1 ? "" : "s",
1995 arena
->stats
.nmadvise
, arena
->stats
.nmadvise
== 1 ? "" : "s",
1996 arena
->stats
.purged
, arena
->stats
.purged
== 1 ? "" : "s");
1997 # ifdef MALLOC_DECOMMIT
1998 malloc_printf("decommit: %I64u decommit%s, %I64u commit%s,"
1999 " %I64u page%s decommitted\n",
2000 arena
->stats
.ndecommit
, (arena
->stats
.ndecommit
== 1) ? "" : "s",
2001 arena
->stats
.ncommit
, (arena
->stats
.ncommit
== 1) ? "" : "s",
2002 arena
->stats
.decommitted
,
2003 (arena
->stats
.decommitted
== 1) ? "" : "s");
2006 malloc_printf(" allocated nmalloc ndalloc\n");
2007 malloc_printf("small: %12Iu %12I64u %12I64u\n",
2008 arena
->stats
.allocated_small
, arena
->stats
.nmalloc_small
,
2009 arena
->stats
.ndalloc_small
);
2010 malloc_printf("large: %12Iu %12I64u %12I64u\n",
2011 arena
->stats
.allocated_large
, arena
->stats
.nmalloc_large
,
2012 arena
->stats
.ndalloc_large
);
2013 malloc_printf("total: %12Iu %12I64u %12I64u\n",
2014 arena
->stats
.allocated_small
+ arena
->stats
.allocated_large
,
2015 arena
->stats
.nmalloc_small
+ arena
->stats
.nmalloc_large
,
2016 arena
->stats
.ndalloc_small
+ arena
->stats
.ndalloc_large
);
2017 malloc_printf("mapped: %12Iu\n", arena
->stats
.mapped
);
2019 malloc_printf("dirty: %zu page%s dirty, %llu sweep%s,"
2020 " %llu madvise%s, %llu page%s purged\n",
2021 arena
->ndirty
, arena
->ndirty
== 1 ? "" : "s",
2022 arena
->stats
.npurge
, arena
->stats
.npurge
== 1 ? "" : "s",
2023 arena
->stats
.nmadvise
, arena
->stats
.nmadvise
== 1 ? "" : "s",
2024 arena
->stats
.purged
, arena
->stats
.purged
== 1 ? "" : "s");
2025 # ifdef MALLOC_DECOMMIT
2026 malloc_printf("decommit: %llu decommit%s, %llu commit%s,"
2027 " %llu page%s decommitted\n",
2028 arena
->stats
.ndecommit
, (arena
->stats
.ndecommit
== 1) ? "" : "s",
2029 arena
->stats
.ncommit
, (arena
->stats
.ncommit
== 1) ? "" : "s",
2030 arena
->stats
.decommitted
,
2031 (arena
->stats
.decommitted
== 1) ? "" : "s");
2034 malloc_printf(" allocated nmalloc ndalloc\n");
2035 malloc_printf("small: %12zu %12llu %12llu\n",
2036 arena
->stats
.allocated_small
, arena
->stats
.nmalloc_small
,
2037 arena
->stats
.ndalloc_small
);
2038 malloc_printf("large: %12zu %12llu %12llu\n",
2039 arena
->stats
.allocated_large
, arena
->stats
.nmalloc_large
,
2040 arena
->stats
.ndalloc_large
);
2041 malloc_printf("total: %12zu %12llu %12llu\n",
2042 arena
->stats
.allocated_small
+ arena
->stats
.allocated_large
,
2043 arena
->stats
.nmalloc_small
+ arena
->stats
.nmalloc_large
,
2044 arena
->stats
.ndalloc_small
+ arena
->stats
.ndalloc_large
);
2045 malloc_printf("mapped: %12zu\n", arena
->stats
.mapped
);
2047 malloc_printf("bins: bin size regs pgs requests newruns"
2048 " reruns maxruns curruns\n");
2049 for (i
= 0, gap_start
= UINT_MAX
; i
< ntbins
+ nqbins
+ nsbins
; i
++) {
2050 if (arena
->bins
[i
].stats
.nrequests
== 0) {
2051 if (gap_start
== UINT_MAX
)
2054 if (gap_start
!= UINT_MAX
) {
2055 if (i
> gap_start
+ 1) {
2056 /* Gap of more than one size class. */
2057 malloc_printf("[%u..%u]\n",
2060 /* Gap of one size class. */
2061 malloc_printf("[%u]\n", gap_start
);
2063 gap_start
= UINT_MAX
;
2066 #if defined(MOZ_MEMORY_WINDOWS)
2067 "%13u %1s %4u %4u %3u %9I64u %9I64u"
2068 " %9I64u %7u %7u\n",
2070 "%13u %1s %4u %4u %3u %9llu %9llu"
2071 " %9llu %7lu %7lu\n",
2074 i
< ntbins
? "T" : i
< ntbins
+ nqbins
? "Q" : "S",
2075 arena
->bins
[i
].reg_size
,
2076 arena
->bins
[i
].nregs
,
2077 arena
->bins
[i
].run_size
>> pagesize_2pow
,
2078 arena
->bins
[i
].stats
.nrequests
,
2079 arena
->bins
[i
].stats
.nruns
,
2080 arena
->bins
[i
].stats
.reruns
,
2081 arena
->bins
[i
].stats
.highruns
,
2082 arena
->bins
[i
].stats
.curruns
);
2085 if (gap_start
!= UINT_MAX
) {
2086 if (i
> gap_start
+ 1) {
2087 /* Gap of more than one size class. */
2088 malloc_printf("[%u..%u]\n", gap_start
, i
- 1);
2090 /* Gap of one size class. */
2091 malloc_printf("[%u]\n", gap_start
);
2098 * End Utility functions/macros.
2100 /******************************************************************************/
2102 * Begin extent tree code.
2106 extent_szad_comp(extent_node_t
*a
, extent_node_t
*b
)
2109 size_t a_size
= a
->size
;
2110 size_t b_size
= b
->size
;
2112 ret
= (a_size
> b_size
) - (a_size
< b_size
);
2114 uintptr_t a_addr
= (uintptr_t)a
->addr
;
2115 uintptr_t b_addr
= (uintptr_t)b
->addr
;
2117 ret
= (a_addr
> b_addr
) - (a_addr
< b_addr
);
2123 /* Wrap red-black tree macros in functions. */
2124 rb_wrap(static, extent_tree_szad_
, extent_tree_t
, extent_node_t
,
2125 link_szad
, extent_szad_comp
)
2128 extent_ad_comp(extent_node_t
*a
, extent_node_t
*b
)
2130 uintptr_t a_addr
= (uintptr_t)a
->addr
;
2131 uintptr_t b_addr
= (uintptr_t)b
->addr
;
2133 return ((a_addr
> b_addr
) - (a_addr
< b_addr
));
2136 /* Wrap red-black tree macros in functions. */
2137 rb_wrap(static, extent_tree_ad_
, extent_tree_t
, extent_node_t
, link_ad
,
2141 * End extent tree code.
2143 /******************************************************************************/
2145 * Begin chunk management functions.
2148 #ifdef MOZ_MEMORY_WINDOWS
2149 #ifdef MOZ_MEMORY_WINCE
2150 #define ALIGN_ADDR2OFFSET(al, ad) \
2151 ((uintptr_t)ad & (al - 1))
2153 pages_map_align(size_t size
, int pfd
, size_t alignment
)
2158 if (size
% alignment
)
2159 size
+= (alignment
- (size
% alignment
));
2160 assert(size
>= alignment
);
2161 ret
= pages_map(NULL
, size
, pfd
);
2162 offset
= ALIGN_ADDR2OFFSET(alignment
, ret
);
2164 /* try to over allocate by the ammount we're offset */
2166 pages_unmap(ret
, size
);
2167 tmp
= VirtualAlloc(NULL
, size
+ alignment
- offset
,
2168 MEM_RESERVE
, PAGE_NOACCESS
);
2169 if (offset
== ALIGN_ADDR2OFFSET(alignment
, tmp
))
2170 ret
= VirtualAlloc((void*)((intptr_t)tmp
+ alignment
2171 - offset
), size
, MEM_COMMIT
,
2174 VirtualFree(tmp
, 0, MEM_RELEASE
);
2175 offset
= ALIGN_ADDR2OFFSET(alignment
, ret
);
2179 /* over allocate to ensure we have an aligned region */
2180 ret
= VirtualAlloc(NULL
, size
+ alignment
, MEM_RESERVE
,
2182 offset
= ALIGN_ADDR2OFFSET(alignment
, ret
);
2183 ret
= VirtualAlloc((void*)((intptr_t)ret
+
2184 alignment
- offset
),
2185 size
, MEM_COMMIT
, PAGE_READWRITE
);
2193 pages_map(void *addr
, size_t size
, int pfd
)
2196 #if defined(MOZ_MEMORY_WINCE) && !defined(MOZ_MEMORY_WINCE6)
2198 assert(addr
== NULL
);
2199 va_ret
= VirtualAlloc(addr
, size
, MEM_RESERVE
, PAGE_NOACCESS
);
2201 ret
= VirtualAlloc(va_ret
, size
, MEM_COMMIT
, PAGE_READWRITE
);
2202 assert(va_ret
== ret
);
2204 ret
= VirtualAlloc(addr
, size
, MEM_COMMIT
| MEM_RESERVE
,
2211 pages_unmap(void *addr
, size_t size
)
2213 if (VirtualFree(addr
, 0, MEM_RELEASE
) == 0) {
2214 #if defined(MOZ_MEMORY_WINCE) && !defined(MOZ_MEMORY_WINCE6)
2215 if (GetLastError() == ERROR_INVALID_PARAMETER
) {
2216 MEMORY_BASIC_INFORMATION info
;
2217 VirtualQuery(addr
, &info
, sizeof(info
));
2218 if (VirtualFree(info
.AllocationBase
, 0, MEM_RELEASE
))
2222 _malloc_message(_getprogname(),
2223 ": (malloc) Error in VirtualFree()\n", "", "");
2228 #elif (defined(MOZ_MEMORY_DARWIN))
2230 pages_map(void *addr
, size_t size
, int pfd
)
2240 flags
= VM_FLAGS_ANYWHERE
;
2242 err
= vm_allocate((vm_map_t
)mach_task_self(), (vm_address_t
*)&ret
,
2243 (vm_size_t
)size
, flags
);
2244 if (err
!= KERN_SUCCESS
)
2247 assert(ret
== NULL
|| (addr
== NULL
&& ret
!= addr
)
2248 || (addr
!= NULL
&& ret
== addr
));
2253 pages_unmap(void *addr
, size_t size
)
2257 err
= vm_deallocate((vm_map_t
)mach_task_self(), (vm_address_t
)addr
,
2259 if (err
!= KERN_SUCCESS
) {
2260 malloc_message(_getprogname(),
2261 ": (malloc) Error in vm_deallocate(): ",
2262 mach_error_string(err
), "\n");
2268 #define VM_COPY_MIN (pagesize << 5)
2270 pages_copy(void *dest
, const void *src
, size_t n
)
2273 assert((void *)((uintptr_t)dest
& ~pagesize_mask
) == dest
);
2274 assert(n
>= VM_COPY_MIN
);
2275 assert((void *)((uintptr_t)src
& ~pagesize_mask
) == src
);
2277 vm_copy(mach_task_self(), (vm_address_t
)src
, (vm_size_t
)n
,
2278 (vm_address_t
)dest
);
2280 #else /* MOZ_MEMORY_DARWIN */
2281 #ifdef JEMALLOC_USES_MAP_ALIGN
2283 pages_map_align(size_t size
, int pfd
, size_t alignment
)
2288 * We don't use MAP_FIXED here, because it can cause the *replacement*
2289 * of existing mappings, and we only want to create new mappings.
2291 #ifdef MALLOC_PAGEFILE
2293 ret
= mmap((void *)alignment
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|
2294 MAP_NOSYNC
| MAP_ALIGN
, pfd
, 0);
2298 ret
= mmap((void *)alignment
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|
2299 MAP_NOSYNC
| MAP_ALIGN
| MAP_ANON
, -1, 0);
2301 assert(ret
!= NULL
);
2303 if (ret
== MAP_FAILED
)
2310 pages_map(void *addr
, size_t size
, int pfd
)
2315 * We don't use MAP_FIXED here, because it can cause the *replacement*
2316 * of existing mappings, and we only want to create new mappings.
2318 #ifdef MALLOC_PAGEFILE
2320 ret
= mmap(addr
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|
2321 MAP_NOSYNC
, pfd
, 0);
2325 ret
= mmap(addr
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|
2328 assert(ret
!= NULL
);
2330 if (ret
== MAP_FAILED
)
2332 else if (addr
!= NULL
&& ret
!= addr
) {
2334 * We succeeded in mapping memory, but not in the right place.
2336 if (munmap(ret
, size
) == -1) {
2337 char buf
[STRERROR_BUF
];
2339 strerror_r(errno
, buf
, sizeof(buf
));
2340 _malloc_message(_getprogname(),
2341 ": (malloc) Error in munmap(): ", buf
, "\n");
2348 assert(ret
== NULL
|| (addr
== NULL
&& ret
!= addr
)
2349 || (addr
!= NULL
&& ret
== addr
));
2354 pages_unmap(void *addr
, size_t size
)
2357 if (munmap(addr
, size
) == -1) {
2358 char buf
[STRERROR_BUF
];
2360 strerror_r(errno
, buf
, sizeof(buf
));
2361 _malloc_message(_getprogname(),
2362 ": (malloc) Error in munmap(): ", buf
, "\n");
2369 #ifdef MALLOC_VALIDATE
2370 static inline malloc_rtree_t
*
2371 malloc_rtree_new(unsigned bits
)
2373 malloc_rtree_t
*ret
;
2374 unsigned bits_per_level
, height
, i
;
2376 bits_per_level
= ffs(pow2_ceil((MALLOC_RTREE_NODESIZE
/
2377 sizeof(void *)))) - 1;
2378 height
= bits
/ bits_per_level
;
2379 if (height
* bits_per_level
!= bits
)
2381 assert(height
* bits_per_level
>= bits
);
2383 ret
= (malloc_rtree_t
*)base_calloc(1, sizeof(malloc_rtree_t
) + (sizeof(unsigned) *
2388 malloc_spin_init(&ret
->lock
);
2389 ret
->height
= height
;
2390 if (bits_per_level
* height
> bits
)
2391 ret
->level2bits
[0] = bits
% bits_per_level
;
2393 ret
->level2bits
[0] = bits_per_level
;
2394 for (i
= 1; i
< height
; i
++)
2395 ret
->level2bits
[i
] = bits_per_level
;
2397 ret
->root
= (void**)base_calloc(1, sizeof(void *) << ret
->level2bits
[0]);
2398 if (ret
->root
== NULL
) {
2400 * We leak the rtree here, since there's no generic base
2409 /* The least significant bits of the key are ignored. */
2410 static inline void *
2411 malloc_rtree_get(malloc_rtree_t
*rtree
, uintptr_t key
)
2415 unsigned i
, lshift
, height
, bits
;
2416 void **node
, **child
;
2418 malloc_spin_lock(&rtree
->lock
);
2419 for (i
= lshift
= 0, height
= rtree
->height
, node
= rtree
->root
;
2421 i
++, lshift
+= bits
, node
= child
) {
2422 bits
= rtree
->level2bits
[i
];
2423 subkey
= (key
<< lshift
) >> ((SIZEOF_PTR
<< 3) - bits
);
2424 child
= (void**)node
[subkey
];
2425 if (child
== NULL
) {
2426 malloc_spin_unlock(&rtree
->lock
);
2431 /* node is a leaf, so it contains values rather than node pointers. */
2432 bits
= rtree
->level2bits
[i
];
2433 subkey
= (key
<< lshift
) >> ((SIZEOF_PTR
<< 3) - bits
);
2435 malloc_spin_unlock(&rtree
->lock
);
2441 malloc_rtree_set(malloc_rtree_t
*rtree
, uintptr_t key
, void *val
)
2444 unsigned i
, lshift
, height
, bits
;
2445 void **node
, **child
;
2447 malloc_spin_lock(&rtree
->lock
);
2448 for (i
= lshift
= 0, height
= rtree
->height
, node
= rtree
->root
;
2450 i
++, lshift
+= bits
, node
= child
) {
2451 bits
= rtree
->level2bits
[i
];
2452 subkey
= (key
<< lshift
) >> ((SIZEOF_PTR
<< 3) - bits
);
2453 child
= (void**)node
[subkey
];
2454 if (child
== NULL
) {
2455 child
= (void**)base_calloc(1, sizeof(void *) <<
2456 rtree
->level2bits
[i
+1]);
2457 if (child
== NULL
) {
2458 malloc_spin_unlock(&rtree
->lock
);
2461 node
[subkey
] = child
;
2465 /* node is a leaf, so it contains values rather than node pointers. */
2466 bits
= rtree
->level2bits
[i
];
2467 subkey
= (key
<< lshift
) >> ((SIZEOF_PTR
<< 3) - bits
);
2469 malloc_spin_unlock(&rtree
->lock
);
2476 chunk_alloc_mmap(size_t size
, bool pagefile
)
2479 #ifndef JEMALLOC_USES_MAP_ALIGN
2484 #ifdef MALLOC_PAGEFILE
2485 if (opt_pagefile
&& pagefile
) {
2486 pfd
= pagefile_init(size
);
2494 * Windows requires that there be a 1:1 mapping between VM
2495 * allocation/deallocation operations. Therefore, take care here to
2496 * acquire the final result via one mapping operation. This means
2497 * unmapping any preliminary result that is not correctly aligned.
2499 * The MALLOC_PAGEFILE code also benefits from this mapping algorithm,
2500 * since it reduces the number of page files.
2503 #ifdef JEMALLOC_USES_MAP_ALIGN
2504 ret
= pages_map_align(size
, pfd
, chunksize
);
2506 ret
= pages_map(NULL
, size
, pfd
);
2510 offset
= CHUNK_ADDR2OFFSET(ret
);
2512 /* Deallocate, then try to allocate at (ret + size - offset). */
2513 pages_unmap(ret
, size
);
2514 ret
= pages_map((void *)((uintptr_t)ret
+ size
- offset
), size
,
2516 while (ret
== NULL
) {
2518 * Over-allocate in order to map a memory region that
2519 * is definitely large enough.
2521 ret
= pages_map(NULL
, size
+ chunksize
, -1);
2525 * Deallocate, then allocate the correct size, within
2526 * the over-sized mapping.
2528 offset
= CHUNK_ADDR2OFFSET(ret
);
2529 pages_unmap(ret
, size
+ chunksize
);
2531 ret
= pages_map(ret
, size
, pfd
);
2533 ret
= pages_map((void *)((uintptr_t)ret
+
2534 chunksize
- offset
), size
, pfd
);
2537 * Failure here indicates a race with another thread, so
2544 #ifdef MALLOC_PAGEFILE
2546 pagefile_close(pfd
);
2550 stats_chunks
.nchunks
+= (size
/ chunksize
);
2555 #ifdef MALLOC_PAGEFILE
2557 pagefile_init(size_t size
)
2561 char pagefile_path
[PATH_MAX
];
2562 char zbuf
[MALLOC_PAGEFILE_WRITE_SIZE
];
2565 * Create a temporary file, then immediately unlink it so that it will
2568 strcpy(pagefile_path
, pagefile_templ
);
2569 ret
= mkstemp(pagefile_path
);
2572 if (unlink(pagefile_path
)) {
2573 char buf
[STRERROR_BUF
];
2575 strerror_r(errno
, buf
, sizeof(buf
));
2576 _malloc_message(_getprogname(), ": (malloc) Error in unlink(\"",
2577 pagefile_path
, "\"):");
2578 _malloc_message(buf
, "\n", "", "");
2584 * Write sequential zeroes to the file in order to assure that disk
2585 * space is committed, with minimal fragmentation. It would be
2586 * sufficient to write one zero per disk block, but that potentially
2587 * results in more system calls, for no real gain.
2589 memset(zbuf
, 0, sizeof(zbuf
));
2590 for (i
= 0; i
< size
; i
+= sizeof(zbuf
)) {
2591 if (write(ret
, zbuf
, sizeof(zbuf
)) != sizeof(zbuf
)) {
2592 if (errno
!= ENOSPC
) {
2593 char buf
[STRERROR_BUF
];
2595 strerror_r(errno
, buf
, sizeof(buf
));
2596 _malloc_message(_getprogname(),
2597 ": (malloc) Error in write(): ", buf
, "\n");
2601 pagefile_close(ret
);
2610 pagefile_close(int pfd
)
2614 char buf
[STRERROR_BUF
];
2616 strerror_r(errno
, buf
, sizeof(buf
));
2617 _malloc_message(_getprogname(),
2618 ": (malloc) Error in close(): ", buf
, "\n");
2626 chunk_recycle_reserve(size_t size
, bool zero
)
2628 extent_node_t
*node
, key
;
2630 #ifdef MALLOC_DECOMMIT
2631 if (size
!= chunksize
)
2637 malloc_mutex_lock(&reserve_mtx
);
2638 node
= extent_tree_szad_nsearch(&reserve_chunks_szad
, &key
);
2640 void *ret
= node
->addr
;
2642 /* Remove node from the tree. */
2643 extent_tree_szad_remove(&reserve_chunks_szad
, node
);
2644 #ifndef MALLOC_DECOMMIT
2645 if (node
->size
== size
) {
2647 assert(node
->size
== size
);
2649 extent_tree_ad_remove(&reserve_chunks_ad
, node
);
2650 base_node_dealloc(node
);
2651 #ifndef MALLOC_DECOMMIT
2654 * Insert the remainder of node's address range as a
2655 * smaller chunk. Its position within reserve_chunks_ad
2658 assert(node
->size
> size
);
2659 node
->addr
= (void *)((uintptr_t)node
->addr
+ size
);
2661 extent_tree_szad_insert(&reserve_chunks_szad
, node
);
2664 reserve_cur
-= size
;
2666 * Try to replenish the reserve if this allocation depleted it.
2668 #ifndef MALLOC_DECOMMIT
2669 if (reserve_cur
< reserve_min
) {
2670 size_t diff
= reserve_min
- reserve_cur
;
2672 while (reserve_cur
< reserve_min
) {
2673 # define diff chunksize
2677 malloc_mutex_unlock(&reserve_mtx
);
2678 chunk
= chunk_alloc_mmap(diff
, true);
2679 malloc_mutex_lock(&reserve_mtx
);
2680 if (chunk
== NULL
) {
2684 seq
= reserve_notify(RESERVE_CND_LOW
,
2688 } while (reserve_cur
< reserve_min
);
2690 extent_node_t
*node
;
2692 node
= chunk_dealloc_reserve(chunk
, diff
);
2696 pages_unmap(chunk
, diff
);
2698 seq
= reserve_notify(
2699 RESERVE_CND_LOW
, size
, seq
);
2702 } while (reserve_cur
< reserve_min
);
2707 malloc_mutex_unlock(&reserve_mtx
);
2709 #ifdef MALLOC_DECOMMIT
2710 pages_commit(ret
, size
);
2714 memset(ret
, 0, size
);
2718 malloc_mutex_unlock(&reserve_mtx
);
2724 chunk_alloc(size_t size
, bool zero
, bool pagefile
)
2729 assert((size
& chunksize_mask
) == 0);
2731 ret
= chunk_recycle_reserve(size
, zero
);
2735 ret
= chunk_alloc_mmap(size
, pagefile
);
2740 /* All strategies for allocation failed. */
2745 stats_chunks
.curchunks
+= (size
/ chunksize
);
2746 if (stats_chunks
.curchunks
> stats_chunks
.highchunks
)
2747 stats_chunks
.highchunks
= stats_chunks
.curchunks
;
2750 #ifdef MALLOC_VALIDATE
2752 if (malloc_rtree_set(chunk_rtree
, (uintptr_t)ret
, ret
)) {
2753 chunk_dealloc(ret
, size
);
2759 assert(CHUNK_ADDR2BASE(ret
) == ret
);
2763 static extent_node_t
*
2764 chunk_dealloc_reserve(void *chunk
, size_t size
)
2766 extent_node_t
*node
;
2768 #ifdef MALLOC_DECOMMIT
2769 if (size
!= chunksize
)
2772 extent_node_t
*prev
, key
;
2774 key
.addr
= (void *)((uintptr_t)chunk
+ size
);
2775 node
= extent_tree_ad_nsearch(&reserve_chunks_ad
, &key
);
2776 /* Try to coalesce forward. */
2777 if (node
!= NULL
&& node
->addr
== key
.addr
) {
2779 * Coalesce chunk with the following address range. This does
2780 * not change the position within reserve_chunks_ad, so only
2781 * remove/insert from/into reserve_chunks_szad.
2783 extent_tree_szad_remove(&reserve_chunks_szad
, node
);
2786 extent_tree_szad_insert(&reserve_chunks_szad
, node
);
2789 /* Coalescing forward failed, so insert a new node. */
2790 node
= base_node_alloc();
2795 extent_tree_ad_insert(&reserve_chunks_ad
, node
);
2796 extent_tree_szad_insert(&reserve_chunks_szad
, node
);
2797 #ifndef MALLOC_DECOMMIT
2800 /* Try to coalesce backward. */
2801 prev
= extent_tree_ad_prev(&reserve_chunks_ad
, node
);
2802 if (prev
!= NULL
&& (void *)((uintptr_t)prev
->addr
+ prev
->size
) ==
2805 * Coalesce chunk with the previous address range. This does
2806 * not change the position within reserve_chunks_ad, so only
2807 * remove/insert node from/into reserve_chunks_szad.
2809 extent_tree_szad_remove(&reserve_chunks_szad
, prev
);
2810 extent_tree_ad_remove(&reserve_chunks_ad
, prev
);
2812 extent_tree_szad_remove(&reserve_chunks_szad
, node
);
2813 node
->addr
= prev
->addr
;
2814 node
->size
+= prev
->size
;
2815 extent_tree_szad_insert(&reserve_chunks_szad
, node
);
2817 base_node_dealloc(prev
);
2821 #ifdef MALLOC_DECOMMIT
2822 pages_decommit(chunk
, size
);
2824 madvise(chunk
, size
, MADV_FREE
);
2827 reserve_cur
+= size
;
2828 if (reserve_cur
> reserve_max
)
2835 chunk_dealloc_mmap(void *chunk
, size_t size
)
2838 pages_unmap(chunk
, size
);
2842 chunk_dealloc(void *chunk
, size_t size
)
2844 extent_node_t
*node
;
2846 assert(chunk
!= NULL
);
2847 assert(CHUNK_ADDR2BASE(chunk
) == chunk
);
2849 assert((size
& chunksize_mask
) == 0);
2852 stats_chunks
.curchunks
-= (size
/ chunksize
);
2854 #ifdef MALLOC_VALIDATE
2855 malloc_rtree_set(chunk_rtree
, (uintptr_t)chunk
, NULL
);
2858 /* Try to merge chunk into the reserve. */
2859 malloc_mutex_lock(&reserve_mtx
);
2860 node
= chunk_dealloc_reserve(chunk
, size
);
2861 malloc_mutex_unlock(&reserve_mtx
);
2863 chunk_dealloc_mmap(chunk
, size
);
2867 * End chunk management functions.
2869 /******************************************************************************/
2875 * Choose an arena based on a per-thread value (fast-path code, calls slow-path
2876 * code if necessary).
2878 static inline arena_t
*
2884 * We can only use TLS if this is a PIC library, since for the static
2885 * library version, libc's malloc is used by TLS allocation, which
2886 * introduces a bootstrapping issue.
2889 if (__isthreaded
== false) {
2890 /* Avoid the overhead of TLS for single-threaded operation. */
2894 # ifdef MOZ_MEMORY_WINDOWS
2895 ret
= (arena_t
*)TlsGetValue(tlsIndex
);
2901 ret
= choose_arena_hard();
2902 assert(ret
!= NULL
);
2905 if (__isthreaded
&& narenas
> 1) {
2909 * Hash _pthread_self() to one of the arenas. There is a prime
2910 * number of arenas, so this has a reasonable chance of
2911 * working. Even so, the hashing can be easily thwarted by
2912 * inconvenient _pthread_self() values. Without specific
2913 * knowledge of how _pthread_self() calculates values, we can't
2914 * easily do much better than this.
2916 ind
= (unsigned long) _pthread_self() % narenas
;
2919 * Optimistially assume that arenas[ind] has been initialized.
2920 * At worst, we find out that some other thread has already
2921 * done so, after acquiring the lock in preparation. Note that
2922 * this lazy locking also has the effect of lazily forcing
2923 * cache coherency; without the lock acquisition, there's no
2924 * guarantee that modification of arenas[ind] by another thread
2925 * would be seen on this CPU for an arbitrary amount of time.
2927 * In general, this approach to modifying a synchronized value
2928 * isn't a good idea, but in this case we only ever modify the
2929 * value once, so things work out well.
2934 * Avoid races with another thread that may have already
2935 * initialized arenas[ind].
2937 malloc_spin_lock(&arenas_lock
);
2938 if (arenas
[ind
] == NULL
)
2939 ret
= arenas_extend((unsigned)ind
);
2942 malloc_spin_unlock(&arenas_lock
);
2948 assert(ret
!= NULL
);
2954 * Choose an arena based on a per-thread value (slow-path code only, called
2955 * only by choose_arena()).
2958 choose_arena_hard(void)
2962 assert(__isthreaded
);
2964 #ifdef MALLOC_BALANCE
2965 /* Seed the PRNG used for arena load balancing. */
2966 SPRN(balance
, (uint32_t)(uintptr_t)(_pthread_self()));
2970 #ifdef MALLOC_BALANCE
2973 ind
= PRN(balance
, narenas_2pow
);
2974 if ((ret
= arenas
[ind
]) == NULL
) {
2975 malloc_spin_lock(&arenas_lock
);
2976 if ((ret
= arenas
[ind
]) == NULL
)
2977 ret
= arenas_extend(ind
);
2978 malloc_spin_unlock(&arenas_lock
);
2981 malloc_spin_lock(&arenas_lock
);
2982 if ((ret
= arenas
[next_arena
]) == NULL
)
2983 ret
= arenas_extend(next_arena
);
2984 next_arena
= (next_arena
+ 1) % narenas
;
2985 malloc_spin_unlock(&arenas_lock
);
2990 #ifdef MOZ_MEMORY_WINDOWS
2991 TlsSetValue(tlsIndex
, ret
);
3001 arena_chunk_comp(arena_chunk_t
*a
, arena_chunk_t
*b
)
3003 uintptr_t a_chunk
= (uintptr_t)a
;
3004 uintptr_t b_chunk
= (uintptr_t)b
;
3009 return ((a_chunk
> b_chunk
) - (a_chunk
< b_chunk
));
3012 /* Wrap red-black tree macros in functions. */
3013 rb_wrap(static, arena_chunk_tree_dirty_
, arena_chunk_tree_t
,
3014 arena_chunk_t
, link_dirty
, arena_chunk_comp
)
3017 arena_run_comp(arena_chunk_map_t
*a
, arena_chunk_map_t
*b
)
3019 uintptr_t a_mapelm
= (uintptr_t)a
;
3020 uintptr_t b_mapelm
= (uintptr_t)b
;
3025 return ((a_mapelm
> b_mapelm
) - (a_mapelm
< b_mapelm
));
3028 /* Wrap red-black tree macros in functions. */
3029 rb_wrap(static, arena_run_tree_
, arena_run_tree_t
, arena_chunk_map_t
, link
,
3033 arena_avail_comp(arena_chunk_map_t
*a
, arena_chunk_map_t
*b
)
3036 size_t a_size
= a
->bits
& ~pagesize_mask
;
3037 size_t b_size
= b
->bits
& ~pagesize_mask
;
3039 ret
= (a_size
> b_size
) - (a_size
< b_size
);
3041 uintptr_t a_mapelm
, b_mapelm
;
3043 if ((a
->bits
& CHUNK_MAP_KEY
) == 0)
3044 a_mapelm
= (uintptr_t)a
;
3047 * Treat keys as though they are lower than anything
3052 b_mapelm
= (uintptr_t)b
;
3054 ret
= (a_mapelm
> b_mapelm
) - (a_mapelm
< b_mapelm
);
3060 /* Wrap red-black tree macros in functions. */
3061 rb_wrap(static, arena_avail_tree_
, arena_avail_tree_t
, arena_chunk_map_t
, link
,
3064 static inline void *
3065 arena_run_reg_alloc(arena_run_t
*run
, arena_bin_t
*bin
)
3068 unsigned i
, mask
, bit
, regind
;
3070 assert(run
->magic
== ARENA_RUN_MAGIC
);
3071 assert(run
->regs_minelm
< bin
->regs_mask_nelms
);
3074 * Move the first check outside the loop, so that run->regs_minelm can
3075 * be updated unconditionally, without the possibility of updating it
3078 i
= run
->regs_minelm
;
3079 mask
= run
->regs_mask
[i
];
3081 /* Usable allocation found. */
3082 bit
= ffs((int)mask
) - 1;
3084 regind
= ((i
<< (SIZEOF_INT_2POW
+ 3)) + bit
);
3085 assert(regind
< bin
->nregs
);
3086 ret
= (void *)(((uintptr_t)run
) + bin
->reg0_offset
3087 + (bin
->reg_size
* regind
));
3090 mask
^= (1U << bit
);
3091 run
->regs_mask
[i
] = mask
;
3096 for (i
++; i
< bin
->regs_mask_nelms
; i
++) {
3097 mask
= run
->regs_mask
[i
];
3099 /* Usable allocation found. */
3100 bit
= ffs((int)mask
) - 1;
3102 regind
= ((i
<< (SIZEOF_INT_2POW
+ 3)) + bit
);
3103 assert(regind
< bin
->nregs
);
3104 ret
= (void *)(((uintptr_t)run
) + bin
->reg0_offset
3105 + (bin
->reg_size
* regind
));
3108 mask
^= (1U << bit
);
3109 run
->regs_mask
[i
] = mask
;
3112 * Make a note that nothing before this element
3113 * contains a free region.
3115 run
->regs_minelm
= i
; /* Low payoff: + (mask == 0); */
3126 arena_run_reg_dalloc(arena_run_t
*run
, arena_bin_t
*bin
, void *ptr
, size_t size
)
3129 * To divide by a number D that is not a power of two we multiply
3130 * by (2^21 / D) and then right shift by 21 positions.
3136 * (X * size_invs[(D >> QUANTUM_2POW_MIN) - 3]) >> SIZE_INV_SHIFT
3138 #define SIZE_INV_SHIFT 21
3139 #define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW_MIN)) + 1)
3140 static const unsigned size_invs
[] = {
3142 SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
3143 SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
3144 SIZE_INV(12),SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
3145 SIZE_INV(16),SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
3146 SIZE_INV(20),SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
3147 SIZE_INV(24),SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
3148 SIZE_INV(28),SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
3149 #if (QUANTUM_2POW_MIN < 4)
3151 SIZE_INV(32), SIZE_INV(33), SIZE_INV(34), SIZE_INV(35),
3152 SIZE_INV(36), SIZE_INV(37), SIZE_INV(38), SIZE_INV(39),
3153 SIZE_INV(40), SIZE_INV(41), SIZE_INV(42), SIZE_INV(43),
3154 SIZE_INV(44), SIZE_INV(45), SIZE_INV(46), SIZE_INV(47),
3155 SIZE_INV(48), SIZE_INV(49), SIZE_INV(50), SIZE_INV(51),
3156 SIZE_INV(52), SIZE_INV(53), SIZE_INV(54), SIZE_INV(55),
3157 SIZE_INV(56), SIZE_INV(57), SIZE_INV(58), SIZE_INV(59),
3158 SIZE_INV(60), SIZE_INV(61), SIZE_INV(62), SIZE_INV(63)
3161 unsigned diff
, regind
, elm
, bit
;
3163 assert(run
->magic
== ARENA_RUN_MAGIC
);
3164 assert(((sizeof(size_invs
)) / sizeof(unsigned)) + 3
3165 >= (SMALL_MAX_DEFAULT
>> QUANTUM_2POW_MIN
));
3168 * Avoid doing division with a variable divisor if possible. Using
3169 * actual division here can reduce allocator throughput by over 20%!
3171 diff
= (unsigned)((uintptr_t)ptr
- (uintptr_t)run
- bin
->reg0_offset
);
3172 if ((size
& (size
- 1)) == 0) {
3174 * log2_table allows fast division of a power of two in the
3177 * (x / divisor) becomes (x >> log2_table[divisor - 1]).
3179 static const unsigned char log2_table
[] = {
3180 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
3181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
3182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
3184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
3191 regind
= (diff
>> log2_table
[size
- 1]);
3192 else if (size
<= 32768)
3193 regind
= diff
>> (8 + log2_table
[(size
>> 8) - 1]);
3196 * The run size is too large for us to use the lookup
3197 * table. Use real division.
3199 regind
= diff
/ size
;
3201 } else if (size
<= ((sizeof(size_invs
) / sizeof(unsigned))
3202 << QUANTUM_2POW_MIN
) + 2) {
3203 regind
= size_invs
[(size
>> QUANTUM_2POW_MIN
) - 3] * diff
;
3204 regind
>>= SIZE_INV_SHIFT
;
3207 * size_invs isn't large enough to handle this size class, so
3208 * calculate regind using actual division. This only happens
3209 * if the user increases small_max via the 'S' runtime
3210 * configuration option.
3212 regind
= diff
/ size
;
3214 assert(diff
== regind
* size
);
3215 assert(regind
< bin
->nregs
);
3217 elm
= regind
>> (SIZEOF_INT_2POW
+ 3);
3218 if (elm
< run
->regs_minelm
)
3219 run
->regs_minelm
= elm
;
3220 bit
= regind
- (elm
<< (SIZEOF_INT_2POW
+ 3));
3221 assert((run
->regs_mask
[elm
] & (1U << bit
)) == 0);
3222 run
->regs_mask
[elm
] |= (1U << bit
);
3224 #undef SIZE_INV_SHIFT
3228 arena_run_split(arena_t
*arena
, arena_run_t
*run
, size_t size
, bool large
,
3231 arena_chunk_t
*chunk
;
3232 size_t old_ndirty
, run_ind
, total_pages
, need_pages
, rem_pages
, i
;
3234 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
3235 old_ndirty
= chunk
->ndirty
;
3236 run_ind
= (unsigned)(((uintptr_t)run
- (uintptr_t)chunk
)
3238 total_pages
= (chunk
->map
[run_ind
].bits
& ~pagesize_mask
) >>
3240 need_pages
= (size
>> pagesize_2pow
);
3241 assert(need_pages
> 0);
3242 assert(need_pages
<= total_pages
);
3243 rem_pages
= total_pages
- need_pages
;
3245 arena_avail_tree_remove(&arena
->runs_avail
, &chunk
->map
[run_ind
]);
3247 /* Keep track of trailing unused pages for later use. */
3248 if (rem_pages
> 0) {
3249 chunk
->map
[run_ind
+need_pages
].bits
= (rem_pages
<<
3250 pagesize_2pow
) | (chunk
->map
[run_ind
+need_pages
].bits
&
3252 chunk
->map
[run_ind
+total_pages
-1].bits
= (rem_pages
<<
3253 pagesize_2pow
) | (chunk
->map
[run_ind
+total_pages
-1].bits
&
3255 arena_avail_tree_insert(&arena
->runs_avail
,
3256 &chunk
->map
[run_ind
+need_pages
]);
3259 for (i
= 0; i
< need_pages
; i
++) {
3260 #ifdef MALLOC_DECOMMIT
3262 * Commit decommitted pages if necessary. If a decommitted
3263 * page is encountered, commit all needed adjacent decommitted
3264 * pages in one operation, in order to reduce system call
3267 if (chunk
->map
[run_ind
+ i
].bits
& CHUNK_MAP_DECOMMITTED
) {
3271 * Advance i+j to just past the index of the last page
3272 * to commit. Clear CHUNK_MAP_DECOMMITTED along the
3275 for (j
= 0; i
+ j
< need_pages
&& (chunk
->map
[run_ind
+
3276 i
+ j
].bits
& CHUNK_MAP_DECOMMITTED
); j
++) {
3277 chunk
->map
[run_ind
+ i
+ j
].bits
^=
3278 CHUNK_MAP_DECOMMITTED
;
3281 pages_commit((void *)((uintptr_t)chunk
+ ((run_ind
+ i
)
3282 << pagesize_2pow
)), (j
<< pagesize_2pow
));
3283 # ifdef MALLOC_STATS
3284 arena
->stats
.ncommit
++;
3286 } else /* No need to zero since commit zeros. */
3289 /* Zero if necessary. */
3291 if ((chunk
->map
[run_ind
+ i
].bits
& CHUNK_MAP_ZEROED
)
3293 VALGRIND_MALLOCLIKE_BLOCK((void *)((uintptr_t)
3294 chunk
+ ((run_ind
+ i
) << pagesize_2pow
)),
3295 pagesize
, 0, false);
3296 memset((void *)((uintptr_t)chunk
+ ((run_ind
3297 + i
) << pagesize_2pow
)), 0, pagesize
);
3298 VALGRIND_FREELIKE_BLOCK((void *)((uintptr_t)
3299 chunk
+ ((run_ind
+ i
) << pagesize_2pow
)),
3301 /* CHUNK_MAP_ZEROED is cleared below. */
3305 /* Update dirty page accounting. */
3306 if (chunk
->map
[run_ind
+ i
].bits
& CHUNK_MAP_DIRTY
) {
3309 /* CHUNK_MAP_DIRTY is cleared below. */
3312 /* Initialize the chunk map. */
3314 chunk
->map
[run_ind
+ i
].bits
= CHUNK_MAP_LARGE
3315 | CHUNK_MAP_ALLOCATED
;
3317 chunk
->map
[run_ind
+ i
].bits
= (size_t)run
3318 | CHUNK_MAP_ALLOCATED
;
3323 * Set the run size only in the first element for large runs. This is
3324 * primarily a debugging aid, since the lack of size info for trailing
3325 * pages only matters if the application tries to operate on an
3329 chunk
->map
[run_ind
].bits
|= size
;
3331 if (chunk
->ndirty
== 0 && old_ndirty
> 0)
3332 arena_chunk_tree_dirty_remove(&arena
->chunks_dirty
, chunk
);
3336 arena_chunk_init(arena_t
*arena
, arena_chunk_t
*chunk
)
3341 VALGRIND_MALLOCLIKE_BLOCK(chunk
, (arena_chunk_header_npages
<<
3342 pagesize_2pow
), 0, false);
3344 arena
->stats
.mapped
+= chunksize
;
3347 chunk
->arena
= arena
;
3350 * Claim that no pages are in use, since the header is merely overhead.
3354 /* Initialize the map to contain one maximal free untouched run. */
3355 run
= (arena_run_t
*)((uintptr_t)chunk
+ (arena_chunk_header_npages
<<
3357 for (i
= 0; i
< arena_chunk_header_npages
; i
++)
3358 chunk
->map
[i
].bits
= 0;
3359 chunk
->map
[i
].bits
= arena_maxclass
3360 #ifdef MALLOC_DECOMMIT
3361 | CHUNK_MAP_DECOMMITTED
3364 for (i
++; i
< chunk_npages
-1; i
++) {
3365 chunk
->map
[i
].bits
=
3366 #ifdef MALLOC_DECOMMIT
3367 CHUNK_MAP_DECOMMITTED
|
3371 chunk
->map
[chunk_npages
-1].bits
= arena_maxclass
3372 #ifdef MALLOC_DECOMMIT
3373 | CHUNK_MAP_DECOMMITTED
3377 #ifdef MALLOC_DECOMMIT
3379 * Start out decommitted, in order to force a closer correspondence
3380 * between dirty pages and committed untouched pages.
3382 pages_decommit(run
, arena_maxclass
);
3383 # ifdef MALLOC_STATS
3384 arena
->stats
.ndecommit
++;
3385 arena
->stats
.decommitted
+= (chunk_npages
- arena_chunk_header_npages
);
3389 /* Insert the run into the runs_avail tree. */
3390 arena_avail_tree_insert(&arena
->runs_avail
,
3391 &chunk
->map
[arena_chunk_header_npages
]);
3395 arena_chunk_dealloc(arena_t
*arena
, arena_chunk_t
*chunk
)
3398 if (arena
->spare
!= NULL
) {
3399 if (arena
->spare
->ndirty
> 0) {
3400 arena_chunk_tree_dirty_remove(
3401 &chunk
->arena
->chunks_dirty
, arena
->spare
);
3402 arena
->ndirty
-= arena
->spare
->ndirty
;
3404 VALGRIND_FREELIKE_BLOCK(arena
->spare
, 0);
3405 chunk_dealloc((void *)arena
->spare
, chunksize
);
3407 arena
->stats
.mapped
-= chunksize
;
3412 * Remove run from runs_avail, regardless of whether this chunk
3413 * will be cached, so that the arena does not use it. Dirty page
3414 * flushing only uses the chunks_dirty tree, so leaving this chunk in
3415 * the chunks_* trees is sufficient for that purpose.
3417 arena_avail_tree_remove(&arena
->runs_avail
,
3418 &chunk
->map
[arena_chunk_header_npages
]);
3420 arena
->spare
= chunk
;
3423 static arena_run_t
*
3424 arena_run_alloc(arena_t
*arena
, arena_bin_t
*bin
, size_t size
, bool large
,
3427 arena_chunk_t
*chunk
;
3429 arena_chunk_map_t
*mapelm
, key
;
3431 assert(size
<= arena_maxclass
);
3432 assert((size
& pagesize_mask
) == 0);
3436 /* Search the arena's chunks for the lowest best fit. */
3437 key
.bits
= size
| CHUNK_MAP_KEY
;
3438 mapelm
= arena_avail_tree_nsearch(&arena
->runs_avail
, &key
);
3439 if (mapelm
!= NULL
) {
3440 arena_chunk_t
*run_chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(mapelm
);
3441 size_t pageind
= ((uintptr_t)mapelm
-
3442 (uintptr_t)run_chunk
->map
) /
3443 sizeof(arena_chunk_map_t
);
3446 chunk_dealloc(chunk
, chunksize
);
3447 run
= (arena_run_t
*)((uintptr_t)run_chunk
+ (pageind
3449 arena_run_split(arena
, run
, size
, large
, zero
);
3453 if (arena
->spare
!= NULL
) {
3454 /* Use the spare. */
3455 chunk
= arena
->spare
;
3456 arena
->spare
= NULL
;
3457 run
= (arena_run_t
*)((uintptr_t)chunk
+
3458 (arena_chunk_header_npages
<< pagesize_2pow
));
3459 /* Insert the run into the runs_avail tree. */
3460 arena_avail_tree_insert(&arena
->runs_avail
,
3461 &chunk
->map
[arena_chunk_header_npages
]);
3462 arena_run_split(arena
, run
, size
, large
, zero
);
3467 * No usable runs. Create a new chunk from which to allocate
3470 if (chunk
== NULL
) {
3474 * Record the chunk allocation sequence number in order
3478 chunk_seq
= arena
->chunk_seq
;
3481 * Drop the arena lock while allocating a chunk, since
3482 * reserve notifications may cause recursive
3483 * allocation. Dropping the lock here opens an
3484 * allocataion race, but we recover.
3486 malloc_mutex_unlock(&arena
->lock
);
3487 chunk
= (arena_chunk_t
*)chunk_alloc(chunksize
, true,
3489 malloc_mutex_lock(&arena
->lock
);
3492 * Check whether a race allowed a usable run to appear.
3494 if (bin
!= NULL
&& (run
= bin
->runcur
) != NULL
&&
3497 chunk_dealloc(chunk
, chunksize
);
3502 * If this thread raced with another such that multiple
3503 * chunks were allocated, make sure that there is still
3504 * inadequate space before using this chunk.
3506 if (chunk_seq
!= arena
->chunk_seq
)
3510 * Check for an error *after* checking for a race,
3511 * since a race could also cause a transient OOM
3518 arena_chunk_init(arena
, chunk
);
3519 run
= (arena_run_t
*)((uintptr_t)chunk
+
3520 (arena_chunk_header_npages
<< pagesize_2pow
));
3521 /* Update page map. */
3522 arena_run_split(arena
, run
, size
, large
, zero
);
3528 arena_purge(arena_t
*arena
)
3530 arena_chunk_t
*chunk
;
3534 rb_foreach_begin(arena_chunk_t
, link_dirty
, &arena
->chunks_dirty
,
3536 ndirty
+= chunk
->ndirty
;
3537 } rb_foreach_end(arena_chunk_t
, link_dirty
, &arena
->chunks_dirty
, chunk
)
3538 assert(ndirty
== arena
->ndirty
);
3540 assert(arena
->ndirty
> opt_dirty_max
);
3543 arena
->stats
.npurge
++;
3547 * Iterate downward through chunks until enough dirty memory has been
3548 * purged. Terminate as soon as possible in order to minimize the
3549 * number of system calls, even if a chunk has only been partially
3552 while (arena
->ndirty
> (opt_dirty_max
>> 1)) {
3553 chunk
= arena_chunk_tree_dirty_last(&arena
->chunks_dirty
);
3554 assert(chunk
!= NULL
);
3556 for (i
= chunk_npages
- 1; chunk
->ndirty
> 0; i
--) {
3557 assert(i
>= arena_chunk_header_npages
);
3559 if (chunk
->map
[i
].bits
& CHUNK_MAP_DIRTY
) {
3560 #ifdef MALLOC_DECOMMIT
3561 assert((chunk
->map
[i
].bits
&
3562 CHUNK_MAP_DECOMMITTED
) == 0);
3564 chunk
->map
[i
].bits
^=
3565 #ifdef MALLOC_DECOMMIT
3566 CHUNK_MAP_DECOMMITTED
|
3569 /* Find adjacent dirty run(s). */
3570 for (npages
= 1; i
> arena_chunk_header_npages
3571 && (chunk
->map
[i
- 1].bits
&
3572 CHUNK_MAP_DIRTY
); npages
++) {
3574 #ifdef MALLOC_DECOMMIT
3575 assert((chunk
->map
[i
].bits
&
3576 CHUNK_MAP_DECOMMITTED
) == 0);
3578 chunk
->map
[i
].bits
^=
3579 #ifdef MALLOC_DECOMMIT
3580 CHUNK_MAP_DECOMMITTED
|
3584 chunk
->ndirty
-= npages
;
3585 arena
->ndirty
-= npages
;
3587 #ifdef MALLOC_DECOMMIT
3588 pages_decommit((void *)((uintptr_t)
3589 chunk
+ (i
<< pagesize_2pow
)),
3590 (npages
<< pagesize_2pow
));
3591 # ifdef MALLOC_STATS
3592 arena
->stats
.ndecommit
++;
3593 arena
->stats
.decommitted
+= npages
;
3596 madvise((void *)((uintptr_t)chunk
+ (i
<<
3597 pagesize_2pow
)), (npages
<< pagesize_2pow
),
3601 arena
->stats
.nmadvise
++;
3602 arena
->stats
.purged
+= npages
;
3604 if (arena
->ndirty
<= (opt_dirty_max
>> 1))
3609 if (chunk
->ndirty
== 0) {
3610 arena_chunk_tree_dirty_remove(&arena
->chunks_dirty
,
3617 arena_run_dalloc(arena_t
*arena
, arena_run_t
*run
, bool dirty
)
3619 arena_chunk_t
*chunk
;
3620 size_t size
, run_ind
, run_pages
;
3622 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(run
);
3623 run_ind
= (size_t)(((uintptr_t)run
- (uintptr_t)chunk
)
3625 assert(run_ind
>= arena_chunk_header_npages
);
3626 assert(run_ind
< chunk_npages
);
3627 if ((chunk
->map
[run_ind
].bits
& CHUNK_MAP_LARGE
) != 0)
3628 size
= chunk
->map
[run_ind
].bits
& ~pagesize_mask
;
3630 size
= run
->bin
->run_size
;
3631 run_pages
= (size
>> pagesize_2pow
);
3633 /* Mark pages as unallocated in the chunk map. */
3637 for (i
= 0; i
< run_pages
; i
++) {
3638 assert((chunk
->map
[run_ind
+ i
].bits
& CHUNK_MAP_DIRTY
)
3640 chunk
->map
[run_ind
+ i
].bits
= CHUNK_MAP_DIRTY
;
3643 if (chunk
->ndirty
== 0) {
3644 arena_chunk_tree_dirty_insert(&arena
->chunks_dirty
,
3647 chunk
->ndirty
+= run_pages
;
3648 arena
->ndirty
+= run_pages
;
3652 for (i
= 0; i
< run_pages
; i
++) {
3653 chunk
->map
[run_ind
+ i
].bits
&= ~(CHUNK_MAP_LARGE
|
3654 CHUNK_MAP_ALLOCATED
);
3657 chunk
->map
[run_ind
].bits
= size
| (chunk
->map
[run_ind
].bits
&
3659 chunk
->map
[run_ind
+run_pages
-1].bits
= size
|
3660 (chunk
->map
[run_ind
+run_pages
-1].bits
& pagesize_mask
);
3662 /* Try to coalesce forward. */
3663 if (run_ind
+ run_pages
< chunk_npages
&&
3664 (chunk
->map
[run_ind
+run_pages
].bits
& CHUNK_MAP_ALLOCATED
) == 0) {
3665 size_t nrun_size
= chunk
->map
[run_ind
+run_pages
].bits
&
3669 * Remove successor from runs_avail; the coalesced run is
3672 arena_avail_tree_remove(&arena
->runs_avail
,
3673 &chunk
->map
[run_ind
+run_pages
]);
3676 run_pages
= size
>> pagesize_2pow
;
3678 assert((chunk
->map
[run_ind
+run_pages
-1].bits
& ~pagesize_mask
)
3680 chunk
->map
[run_ind
].bits
= size
| (chunk
->map
[run_ind
].bits
&
3682 chunk
->map
[run_ind
+run_pages
-1].bits
= size
|
3683 (chunk
->map
[run_ind
+run_pages
-1].bits
& pagesize_mask
);
3686 /* Try to coalesce backward. */
3687 if (run_ind
> arena_chunk_header_npages
&& (chunk
->map
[run_ind
-1].bits
&
3688 CHUNK_MAP_ALLOCATED
) == 0) {
3689 size_t prun_size
= chunk
->map
[run_ind
-1].bits
& ~pagesize_mask
;
3691 run_ind
-= prun_size
>> pagesize_2pow
;
3694 * Remove predecessor from runs_avail; the coalesced run is
3697 arena_avail_tree_remove(&arena
->runs_avail
,
3698 &chunk
->map
[run_ind
]);
3701 run_pages
= size
>> pagesize_2pow
;
3703 assert((chunk
->map
[run_ind
].bits
& ~pagesize_mask
) ==
3705 chunk
->map
[run_ind
].bits
= size
| (chunk
->map
[run_ind
].bits
&
3707 chunk
->map
[run_ind
+run_pages
-1].bits
= size
|
3708 (chunk
->map
[run_ind
+run_pages
-1].bits
& pagesize_mask
);
3711 /* Insert into runs_avail, now that coalescing is complete. */
3712 arena_avail_tree_insert(&arena
->runs_avail
, &chunk
->map
[run_ind
]);
3714 /* Deallocate chunk if it is now completely unused. */
3715 if ((chunk
->map
[arena_chunk_header_npages
].bits
& (~pagesize_mask
|
3716 CHUNK_MAP_ALLOCATED
)) == arena_maxclass
)
3717 arena_chunk_dealloc(arena
, chunk
);
3719 /* Enforce opt_dirty_max. */
3720 if (arena
->ndirty
> opt_dirty_max
)
3725 arena_run_trim_head(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
3726 size_t oldsize
, size_t newsize
)
3728 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> pagesize_2pow
;
3729 size_t head_npages
= (oldsize
- newsize
) >> pagesize_2pow
;
3731 assert(oldsize
> newsize
);
3734 * Update the chunk map so that arena_run_dalloc() can treat the
3735 * leading run as separately allocated.
3737 chunk
->map
[pageind
].bits
= (oldsize
- newsize
) | CHUNK_MAP_LARGE
|
3738 CHUNK_MAP_ALLOCATED
;
3739 chunk
->map
[pageind
+head_npages
].bits
= newsize
| CHUNK_MAP_LARGE
|
3740 CHUNK_MAP_ALLOCATED
;
3742 arena_run_dalloc(arena
, run
, false);
3746 arena_run_trim_tail(arena_t
*arena
, arena_chunk_t
*chunk
, arena_run_t
*run
,
3747 size_t oldsize
, size_t newsize
, bool dirty
)
3749 size_t pageind
= ((uintptr_t)run
- (uintptr_t)chunk
) >> pagesize_2pow
;
3750 size_t npages
= newsize
>> pagesize_2pow
;
3752 assert(oldsize
> newsize
);
3755 * Update the chunk map so that arena_run_dalloc() can treat the
3756 * trailing run as separately allocated.
3758 chunk
->map
[pageind
].bits
= newsize
| CHUNK_MAP_LARGE
|
3759 CHUNK_MAP_ALLOCATED
;
3760 chunk
->map
[pageind
+npages
].bits
= (oldsize
- newsize
) | CHUNK_MAP_LARGE
3761 | CHUNK_MAP_ALLOCATED
;
3763 arena_run_dalloc(arena
, (arena_run_t
*)((uintptr_t)run
+ newsize
),
3767 static arena_run_t
*
3768 arena_bin_nonfull_run_get(arena_t
*arena
, arena_bin_t
*bin
)
3770 arena_chunk_map_t
*mapelm
;
3772 unsigned i
, remainder
;
3774 /* Look for a usable run. */
3775 mapelm
= arena_run_tree_first(&bin
->runs
);
3776 if (mapelm
!= NULL
) {
3777 /* run is guaranteed to have available space. */
3778 arena_run_tree_remove(&bin
->runs
, mapelm
);
3779 run
= (arena_run_t
*)(mapelm
->bits
& ~pagesize_mask
);
3781 bin
->stats
.reruns
++;
3785 /* No existing runs have any space available. */
3787 /* Allocate a new run. */
3788 run
= arena_run_alloc(arena
, bin
, bin
->run_size
, false, false);
3792 * Don't initialize if a race in arena_run_alloc() allowed an existing
3793 * run to become usable.
3795 if (run
== bin
->runcur
)
3798 VALGRIND_MALLOCLIKE_BLOCK(run
, sizeof(arena_run_t
) + (sizeof(unsigned) *
3799 (bin
->regs_mask_nelms
- 1)), 0, false);
3801 /* Initialize run internals. */
3804 for (i
= 0; i
< bin
->regs_mask_nelms
- 1; i
++)
3805 run
->regs_mask
[i
] = UINT_MAX
;
3806 remainder
= bin
->nregs
& ((1U << (SIZEOF_INT_2POW
+ 3)) - 1);
3808 run
->regs_mask
[i
] = UINT_MAX
;
3810 /* The last element has spare bits that need to be unset. */
3811 run
->regs_mask
[i
] = (UINT_MAX
>> ((1U << (SIZEOF_INT_2POW
+ 3))
3815 run
->regs_minelm
= 0;
3817 run
->nfree
= bin
->nregs
;
3819 run
->magic
= ARENA_RUN_MAGIC
;
3824 bin
->stats
.curruns
++;
3825 if (bin
->stats
.curruns
> bin
->stats
.highruns
)
3826 bin
->stats
.highruns
= bin
->stats
.curruns
;
3831 /* bin->runcur must have space available before this function is called. */
3832 static inline void *
3833 arena_bin_malloc_easy(arena_t
*arena
, arena_bin_t
*bin
, arena_run_t
*run
)
3837 assert(run
->magic
== ARENA_RUN_MAGIC
);
3838 assert(run
->nfree
> 0);
3840 ret
= arena_run_reg_alloc(run
, bin
);
3841 assert(ret
!= NULL
);
3847 /* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
3849 arena_bin_malloc_hard(arena_t
*arena
, arena_bin_t
*bin
)
3852 bin
->runcur
= arena_bin_nonfull_run_get(arena
, bin
);
3853 if (bin
->runcur
== NULL
)
3855 assert(bin
->runcur
->magic
== ARENA_RUN_MAGIC
);
3856 assert(bin
->runcur
->nfree
> 0);
3858 return (arena_bin_malloc_easy(arena
, bin
, bin
->runcur
));
3862 * Calculate bin->run_size such that it meets the following constraints:
3864 * *) bin->run_size >= min_run_size
3865 * *) bin->run_size <= arena_maxclass
3866 * *) bin->run_size <= RUN_MAX_SMALL
3867 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
3869 * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
3870 * also calculated here, since these settings are all interdependent.
3873 arena_bin_run_size_calc(arena_bin_t
*bin
, size_t min_run_size
)
3875 size_t try_run_size
, good_run_size
;
3876 unsigned good_nregs
, good_mask_nelms
, good_reg0_offset
;
3877 unsigned try_nregs
, try_mask_nelms
, try_reg0_offset
;
3879 assert(min_run_size
>= pagesize
);
3880 assert(min_run_size
<= arena_maxclass
);
3881 assert(min_run_size
<= RUN_MAX_SMALL
);
3884 * Calculate known-valid settings before entering the run_size
3885 * expansion loop, so that the first part of the loop always copies
3888 * The do..while loop iteratively reduces the number of regions until
3889 * the run header and the regions no longer overlap. A closed formula
3890 * would be quite messy, since there is an interdependency between the
3891 * header's mask length and the number of regions.
3893 try_run_size
= min_run_size
;
3894 try_nregs
= ((try_run_size
- sizeof(arena_run_t
)) / bin
->reg_size
)
3895 + 1; /* Counter-act try_nregs-- in loop. */
3898 try_mask_nelms
= (try_nregs
>> (SIZEOF_INT_2POW
+ 3)) +
3899 ((try_nregs
& ((1U << (SIZEOF_INT_2POW
+ 3)) - 1)) ? 1 : 0);
3900 try_reg0_offset
= try_run_size
- (try_nregs
* bin
->reg_size
);
3901 } while (sizeof(arena_run_t
) + (sizeof(unsigned) * (try_mask_nelms
- 1))
3904 /* run_size expansion loop. */
3907 * Copy valid settings before trying more aggressive settings.
3909 good_run_size
= try_run_size
;
3910 good_nregs
= try_nregs
;
3911 good_mask_nelms
= try_mask_nelms
;
3912 good_reg0_offset
= try_reg0_offset
;
3914 /* Try more aggressive settings. */
3915 try_run_size
+= pagesize
;
3916 try_nregs
= ((try_run_size
- sizeof(arena_run_t
)) /
3917 bin
->reg_size
) + 1; /* Counter-act try_nregs-- in loop. */
3920 try_mask_nelms
= (try_nregs
>> (SIZEOF_INT_2POW
+ 3)) +
3921 ((try_nregs
& ((1U << (SIZEOF_INT_2POW
+ 3)) - 1)) ?
3923 try_reg0_offset
= try_run_size
- (try_nregs
*
3925 } while (sizeof(arena_run_t
) + (sizeof(unsigned) *
3926 (try_mask_nelms
- 1)) > try_reg0_offset
);
3927 } while (try_run_size
<= arena_maxclass
&& try_run_size
<= RUN_MAX_SMALL
3928 && RUN_MAX_OVRHD
* (bin
->reg_size
<< 3) > RUN_MAX_OVRHD_RELAX
3929 && (try_reg0_offset
<< RUN_BFP
) > RUN_MAX_OVRHD
* try_run_size
);
3931 assert(sizeof(arena_run_t
) + (sizeof(unsigned) * (good_mask_nelms
- 1))
3932 <= good_reg0_offset
);
3933 assert((good_mask_nelms
<< (SIZEOF_INT_2POW
+ 3)) >= good_nregs
);
3935 /* Copy final settings. */
3936 bin
->run_size
= good_run_size
;
3937 bin
->nregs
= good_nregs
;
3938 bin
->regs_mask_nelms
= good_mask_nelms
;
3939 bin
->reg0_offset
= good_reg0_offset
;
3941 return (good_run_size
);
3944 #ifdef MALLOC_BALANCE
3946 arena_lock_balance(arena_t
*arena
)
3948 unsigned contention
;
3950 contention
= malloc_spin_lock(&arena
->lock
);
3953 * Calculate the exponentially averaged contention for this
3954 * arena. Due to integer math always rounding down, this value
3955 * decays somewhat faster then normal.
3957 arena
->contention
= (((uint64_t)arena
->contention
3958 * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW
)-1))
3959 + (uint64_t)contention
) >> BALANCE_ALPHA_INV_2POW
;
3960 if (arena
->contention
>= opt_balance_threshold
)
3961 arena_lock_balance_hard(arena
);
3966 arena_lock_balance_hard(arena_t
*arena
)
3970 arena
->contention
= 0;
3972 arena
->stats
.nbalance
++;
3974 ind
= PRN(balance
, narenas_2pow
);
3975 if (arenas
[ind
] != NULL
) {
3976 #ifdef MOZ_MEMORY_WINDOWS
3977 TlsSetValue(tlsIndex
, arenas
[ind
]);
3979 arenas_map
= arenas
[ind
];
3982 malloc_spin_lock(&arenas_lock
);
3983 if (arenas
[ind
] != NULL
) {
3984 #ifdef MOZ_MEMORY_WINDOWS
3985 TlsSetValue(tlsIndex
, arenas
[ind
]);
3987 arenas_map
= arenas
[ind
];
3990 #ifdef MOZ_MEMORY_WINDOWS
3991 TlsSetValue(tlsIndex
, arenas_extend(ind
));
3993 arenas_map
= arenas_extend(ind
);
3996 malloc_spin_unlock(&arenas_lock
);
4001 static inline void *
4002 arena_malloc_small(arena_t
*arena
, size_t size
, bool zero
)
4008 if (size
< small_min
) {
4010 size
= pow2_ceil(size
);
4011 bin
= &arena
->bins
[ffs((int)(size
>> (TINY_MIN_2POW
+
4013 #if (!defined(NDEBUG) || defined(MALLOC_STATS))
4015 * Bin calculation is always correct, but we may need
4016 * to fix size for the purposes of assertions and/or
4019 if (size
< (1U << TINY_MIN_2POW
))
4020 size
= (1U << TINY_MIN_2POW
);
4022 } else if (size
<= small_max
) {
4023 /* Quantum-spaced. */
4024 size
= QUANTUM_CEILING(size
);
4025 bin
= &arena
->bins
[ntbins
+ (size
>> opt_quantum_2pow
)
4029 size
= pow2_ceil(size
);
4030 bin
= &arena
->bins
[ntbins
+ nqbins
4031 + (ffs((int)(size
>> opt_small_max_2pow
)) - 2)];
4033 assert(size
== bin
->reg_size
);
4035 #ifdef MALLOC_BALANCE
4036 arena_lock_balance(arena
);
4038 malloc_spin_lock(&arena
->lock
);
4040 if ((run
= bin
->runcur
) != NULL
&& run
->nfree
> 0)
4041 ret
= arena_bin_malloc_easy(arena
, bin
, run
);
4043 ret
= arena_bin_malloc_hard(arena
, bin
);
4046 malloc_spin_unlock(&arena
->lock
);
4051 bin
->stats
.nrequests
++;
4052 arena
->stats
.nmalloc_small
++;
4053 arena
->stats
.allocated_small
+= size
;
4055 malloc_spin_unlock(&arena
->lock
);
4057 VALGRIND_MALLOCLIKE_BLOCK(ret
, size
, 0, zero
);
4058 if (zero
== false) {
4061 memset(ret
, 0xa5, size
);
4063 memset(ret
, 0, size
);
4066 memset(ret
, 0, size
);
4072 arena_malloc_large(arena_t
*arena
, size_t size
, bool zero
)
4076 /* Large allocation. */
4077 size
= PAGE_CEILING(size
);
4078 #ifdef MALLOC_BALANCE
4079 arena_lock_balance(arena
);
4081 malloc_spin_lock(&arena
->lock
);
4083 ret
= (void *)arena_run_alloc(arena
, NULL
, size
, true, zero
);
4085 malloc_spin_unlock(&arena
->lock
);
4089 arena
->stats
.nmalloc_large
++;
4090 arena
->stats
.allocated_large
+= size
;
4092 malloc_spin_unlock(&arena
->lock
);
4094 VALGRIND_MALLOCLIKE_BLOCK(ret
, size
, 0, zero
);
4095 if (zero
== false) {
4098 memset(ret
, 0xa5, size
);
4100 memset(ret
, 0, size
);
4107 static inline void *
4108 arena_malloc(arena_t
*arena
, size_t size
, bool zero
)
4111 assert(arena
!= NULL
);
4112 assert(arena
->magic
== ARENA_MAGIC
);
4114 assert(QUANTUM_CEILING(size
) <= arena_maxclass
);
4116 if (size
<= bin_maxclass
) {
4117 return (arena_malloc_small(arena
, size
, zero
));
4119 return (arena_malloc_large(arena
, size
, zero
));
4122 static inline void *
4123 imalloc(size_t size
)
4128 if (size
<= arena_maxclass
)
4129 return (arena_malloc(choose_arena(), size
, false));
4131 return (huge_malloc(size
, false));
4134 static inline void *
4135 icalloc(size_t size
)
4138 if (size
<= arena_maxclass
)
4139 return (arena_malloc(choose_arena(), size
, true));
4141 return (huge_malloc(size
, true));
4144 /* Only handles large allocations that require more than page alignment. */
4146 arena_palloc(arena_t
*arena
, size_t alignment
, size_t size
, size_t alloc_size
)
4150 arena_chunk_t
*chunk
;
4152 assert((size
& pagesize_mask
) == 0);
4153 assert((alignment
& pagesize_mask
) == 0);
4155 #ifdef MALLOC_BALANCE
4156 arena_lock_balance(arena
);
4158 malloc_spin_lock(&arena
->lock
);
4160 ret
= (void *)arena_run_alloc(arena
, NULL
, alloc_size
, true, false);
4162 malloc_spin_unlock(&arena
->lock
);
4166 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ret
);
4168 offset
= (uintptr_t)ret
& (alignment
- 1);
4169 assert((offset
& pagesize_mask
) == 0);
4170 assert(offset
< alloc_size
);
4172 arena_run_trim_tail(arena
, chunk
, (arena_run_t
*)ret
, alloc_size
, size
, false);
4174 size_t leadsize
, trailsize
;
4176 leadsize
= alignment
- offset
;
4178 arena_run_trim_head(arena
, chunk
, (arena_run_t
*)ret
, alloc_size
,
4179 alloc_size
- leadsize
);
4180 ret
= (void *)((uintptr_t)ret
+ leadsize
);
4183 trailsize
= alloc_size
- leadsize
- size
;
4184 if (trailsize
!= 0) {
4185 /* Trim trailing space. */
4186 assert(trailsize
< alloc_size
);
4187 arena_run_trim_tail(arena
, chunk
, (arena_run_t
*)ret
, size
+ trailsize
,
4193 arena
->stats
.nmalloc_large
++;
4194 arena
->stats
.allocated_large
+= size
;
4196 malloc_spin_unlock(&arena
->lock
);
4198 VALGRIND_MALLOCLIKE_BLOCK(ret
, size
, 0, false);
4201 memset(ret
, 0xa5, size
);
4203 memset(ret
, 0, size
);
4208 static inline void *
4209 ipalloc(size_t alignment
, size_t size
)
4215 * Round size up to the nearest multiple of alignment.
4217 * This done, we can take advantage of the fact that for each small
4218 * size class, every object is aligned at the smallest power of two
4219 * that is non-zero in the base two representation of the size. For
4222 * Size | Base 2 | Minimum alignment
4223 * -----+----------+------------------
4225 * 144 | 10100000 | 32
4226 * 192 | 11000000 | 64
4228 * Depending on runtime settings, it is possible that arena_malloc()
4229 * will further round up to a power of two, but that never causes
4230 * correctness issues.
4232 ceil_size
= (size
+ (alignment
- 1)) & (-alignment
);
4234 * (ceil_size < size) protects against the combination of maximal
4235 * alignment and size greater than maximal alignment.
4237 if (ceil_size
< size
) {
4238 /* size_t overflow. */
4242 if (ceil_size
<= pagesize
|| (alignment
<= pagesize
4243 && ceil_size
<= arena_maxclass
))
4244 ret
= arena_malloc(choose_arena(), ceil_size
, false);
4249 * We can't achieve sub-page alignment, so round up alignment
4250 * permanently; it makes later calculations simpler.
4252 alignment
= PAGE_CEILING(alignment
);
4253 ceil_size
= PAGE_CEILING(size
);
4255 * (ceil_size < size) protects against very large sizes within
4256 * pagesize of SIZE_T_MAX.
4258 * (ceil_size + alignment < ceil_size) protects against the
4259 * combination of maximal alignment and ceil_size large enough
4260 * to cause overflow. This is similar to the first overflow
4261 * check above, but it needs to be repeated due to the new
4262 * ceil_size value, which may now be *equal* to maximal
4263 * alignment, whereas before we only detected overflow if the
4264 * original size was *greater* than maximal alignment.
4266 if (ceil_size
< size
|| ceil_size
+ alignment
< ceil_size
) {
4267 /* size_t overflow. */
4272 * Calculate the size of the over-size run that arena_palloc()
4273 * would need to allocate in order to guarantee the alignment.
4275 if (ceil_size
>= alignment
)
4276 run_size
= ceil_size
+ alignment
- pagesize
;
4279 * It is possible that (alignment << 1) will cause
4280 * overflow, but it doesn't matter because we also
4281 * subtract pagesize, which in the case of overflow
4282 * leaves us with a very large run_size. That causes
4283 * the first conditional below to fail, which means
4284 * that the bogus run_size value never gets used for
4285 * anything important.
4287 run_size
= (alignment
<< 1) - pagesize
;
4290 if (run_size
<= arena_maxclass
) {
4291 ret
= arena_palloc(choose_arena(), alignment
, ceil_size
,
4293 } else if (alignment
<= chunksize
)
4294 ret
= huge_malloc(ceil_size
, false);
4296 ret
= huge_palloc(alignment
, ceil_size
);
4299 assert(((uintptr_t)ret
& (alignment
- 1)) == 0);
4303 /* Return the size of the allocation pointed to by ptr. */
4305 arena_salloc(const void *ptr
)
4308 arena_chunk_t
*chunk
;
4309 size_t pageind
, mapbits
;
4311 assert(ptr
!= NULL
);
4312 assert(CHUNK_ADDR2BASE(ptr
) != ptr
);
4314 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
4315 pageind
= (((uintptr_t)ptr
- (uintptr_t)chunk
) >> pagesize_2pow
);
4316 mapbits
= chunk
->map
[pageind
].bits
;
4317 assert((mapbits
& CHUNK_MAP_ALLOCATED
) != 0);
4318 if ((mapbits
& CHUNK_MAP_LARGE
) == 0) {
4319 arena_run_t
*run
= (arena_run_t
*)(mapbits
& ~pagesize_mask
);
4320 assert(run
->magic
== ARENA_RUN_MAGIC
);
4321 ret
= run
->bin
->reg_size
;
4323 ret
= mapbits
& ~pagesize_mask
;
4330 #if (defined(MALLOC_VALIDATE) || defined(MOZ_MEMORY_DARWIN))
4332 * Validate ptr before assuming that it points to an allocation. Currently,
4333 * the following validation is performed:
4335 * + Check that ptr is not NULL.
4337 * + Check that ptr lies within a mapped chunk.
4339 static inline size_t
4340 isalloc_validate(const void *ptr
)
4342 arena_chunk_t
*chunk
;
4344 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
4348 if (malloc_rtree_get(chunk_rtree
, (uintptr_t)chunk
) == NULL
)
4352 assert(chunk
->arena
->magic
== ARENA_MAGIC
);
4353 return (arena_salloc(ptr
));
4356 extent_node_t
*node
;
4360 key
.addr
= (void *)chunk
;
4361 malloc_mutex_lock(&huge_mtx
);
4362 node
= extent_tree_ad_search(&huge
, &key
);
4367 malloc_mutex_unlock(&huge_mtx
);
4373 static inline size_t
4374 isalloc(const void *ptr
)
4377 arena_chunk_t
*chunk
;
4379 assert(ptr
!= NULL
);
4381 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
4384 assert(chunk
->arena
->magic
== ARENA_MAGIC
);
4386 ret
= arena_salloc(ptr
);
4388 extent_node_t
*node
, key
;
4390 /* Chunk (huge allocation). */
4392 malloc_mutex_lock(&huge_mtx
);
4394 /* Extract from tree of huge allocations. */
4395 key
.addr
= __DECONST(void *, ptr
);
4396 node
= extent_tree_ad_search(&huge
, &key
);
4397 assert(node
!= NULL
);
4401 malloc_mutex_unlock(&huge_mtx
);
4408 arena_dalloc_small(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
4409 arena_chunk_map_t
*mapelm
)
4415 run
= (arena_run_t
*)(mapelm
->bits
& ~pagesize_mask
);
4416 assert(run
->magic
== ARENA_RUN_MAGIC
);
4418 size
= bin
->reg_size
;
4422 memset(ptr
, 0x5a, size
);
4425 arena_run_reg_dalloc(run
, bin
, ptr
, size
);
4428 if (run
->nfree
== bin
->nregs
) {
4429 /* Deallocate run. */
4430 if (run
== bin
->runcur
)
4432 else if (bin
->nregs
!= 1) {
4433 size_t run_pageind
= (((uintptr_t)run
-
4434 (uintptr_t)chunk
)) >> pagesize_2pow
;
4435 arena_chunk_map_t
*run_mapelm
=
4436 &chunk
->map
[run_pageind
];
4438 * This block's conditional is necessary because if the
4439 * run only contains one region, then it never gets
4440 * inserted into the non-full runs tree.
4442 assert(arena_run_tree_search(&bin
->runs
, run_mapelm
) ==
4444 arena_run_tree_remove(&bin
->runs
, run_mapelm
);
4449 VALGRIND_FREELIKE_BLOCK(run
, 0);
4450 arena_run_dalloc(arena
, run
, true);
4452 bin
->stats
.curruns
--;
4454 } else if (run
->nfree
== 1 && run
!= bin
->runcur
) {
4456 * Make sure that bin->runcur always refers to the lowest
4457 * non-full run, if one exists.
4459 if (bin
->runcur
== NULL
)
4461 else if ((uintptr_t)run
< (uintptr_t)bin
->runcur
) {
4462 /* Switch runcur. */
4463 if (bin
->runcur
->nfree
> 0) {
4464 arena_chunk_t
*runcur_chunk
=
4465 (arena_chunk_t
*)CHUNK_ADDR2BASE(bin
->runcur
);
4466 size_t runcur_pageind
=
4467 (((uintptr_t)bin
->runcur
-
4468 (uintptr_t)runcur_chunk
)) >> pagesize_2pow
;
4469 arena_chunk_map_t
*runcur_mapelm
=
4470 &runcur_chunk
->map
[runcur_pageind
];
4472 /* Insert runcur. */
4473 assert(arena_run_tree_search(&bin
->runs
,
4474 runcur_mapelm
) == NULL
);
4475 arena_run_tree_insert(&bin
->runs
,
4480 size_t run_pageind
= (((uintptr_t)run
-
4481 (uintptr_t)chunk
)) >> pagesize_2pow
;
4482 arena_chunk_map_t
*run_mapelm
=
4483 &chunk
->map
[run_pageind
];
4485 assert(arena_run_tree_search(&bin
->runs
, run_mapelm
) ==
4487 arena_run_tree_insert(&bin
->runs
, run_mapelm
);
4491 arena
->stats
.allocated_small
-= size
;
4492 arena
->stats
.ndalloc_small
++;
4497 arena_dalloc_large(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
)
4499 /* Large allocation. */
4500 malloc_spin_lock(&arena
->lock
);
4503 #ifndef MALLOC_STATS
4508 size_t pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >>
4510 size_t size
= chunk
->map
[pageind
].bits
& ~pagesize_mask
;
4516 memset(ptr
, 0x5a, size
);
4519 arena
->stats
.allocated_large
-= size
;
4523 arena
->stats
.ndalloc_large
++;
4526 arena_run_dalloc(arena
, (arena_run_t
*)ptr
, true);
4527 malloc_spin_unlock(&arena
->lock
);
4531 arena_dalloc(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
)
4534 arena_chunk_map_t
*mapelm
;
4536 assert(arena
!= NULL
);
4537 assert(arena
->magic
== ARENA_MAGIC
);
4538 assert(chunk
->arena
== arena
);
4539 assert(ptr
!= NULL
);
4540 assert(CHUNK_ADDR2BASE(ptr
) != ptr
);
4542 pageind
= (((uintptr_t)ptr
- (uintptr_t)chunk
) >> pagesize_2pow
);
4543 mapelm
= &chunk
->map
[pageind
];
4544 assert((mapelm
->bits
& CHUNK_MAP_ALLOCATED
) != 0);
4545 if ((mapelm
->bits
& CHUNK_MAP_LARGE
) == 0) {
4546 /* Small allocation. */
4547 malloc_spin_lock(&arena
->lock
);
4548 arena_dalloc_small(arena
, chunk
, ptr
, mapelm
);
4549 malloc_spin_unlock(&arena
->lock
);
4551 arena_dalloc_large(arena
, chunk
, ptr
);
4552 VALGRIND_FREELIKE_BLOCK(ptr
, 0);
4558 arena_chunk_t
*chunk
;
4560 assert(ptr
!= NULL
);
4562 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
4564 arena_dalloc(chunk
->arena
, chunk
, ptr
);
4570 arena_ralloc_large_shrink(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
4571 size_t size
, size_t oldsize
)
4574 assert(size
< oldsize
);
4577 * Shrink the run, and make trailing pages available for other
4580 #ifdef MALLOC_BALANCE
4581 arena_lock_balance(arena
);
4583 malloc_spin_lock(&arena
->lock
);
4585 arena_run_trim_tail(arena
, chunk
, (arena_run_t
*)ptr
, oldsize
, size
,
4588 arena
->stats
.allocated_large
-= oldsize
- size
;
4590 malloc_spin_unlock(&arena
->lock
);
4594 arena_ralloc_large_grow(arena_t
*arena
, arena_chunk_t
*chunk
, void *ptr
,
4595 size_t size
, size_t oldsize
)
4597 size_t pageind
= ((uintptr_t)ptr
- (uintptr_t)chunk
) >> pagesize_2pow
;
4598 size_t npages
= oldsize
>> pagesize_2pow
;
4600 assert(oldsize
== (chunk
->map
[pageind
].bits
& ~pagesize_mask
));
4602 /* Try to extend the run. */
4603 assert(size
> oldsize
);
4604 #ifdef MALLOC_BALANCE
4605 arena_lock_balance(arena
);
4607 malloc_spin_lock(&arena
->lock
);
4609 if (pageind
+ npages
< chunk_npages
&& (chunk
->map
[pageind
+npages
].bits
4610 & CHUNK_MAP_ALLOCATED
) == 0 && (chunk
->map
[pageind
+npages
].bits
&
4611 ~pagesize_mask
) >= size
- oldsize
) {
4613 * The next run is available and sufficiently large. Split the
4614 * following run, then merge the first part with the existing
4617 arena_run_split(arena
, (arena_run_t
*)((uintptr_t)chunk
+
4618 ((pageind
+npages
) << pagesize_2pow
)), size
- oldsize
, true,
4621 chunk
->map
[pageind
].bits
= size
| CHUNK_MAP_LARGE
|
4622 CHUNK_MAP_ALLOCATED
;
4623 chunk
->map
[pageind
+npages
].bits
= CHUNK_MAP_LARGE
|
4624 CHUNK_MAP_ALLOCATED
;
4627 arena
->stats
.allocated_large
+= size
- oldsize
;
4629 malloc_spin_unlock(&arena
->lock
);
4632 malloc_spin_unlock(&arena
->lock
);
4638 * Try to resize a large allocation, in order to avoid copying. This will
4639 * always fail if growing an object, and the following run is already in use.
4642 arena_ralloc_large(void *ptr
, size_t size
, size_t oldsize
)
4646 psize
= PAGE_CEILING(size
);
4647 if (psize
== oldsize
) {
4648 /* Same size class. */
4650 if (opt_junk
&& size
< oldsize
) {
4651 memset((void *)((uintptr_t)ptr
+ size
), 0x5a, oldsize
-
4657 arena_chunk_t
*chunk
;
4660 chunk
= (arena_chunk_t
*)CHUNK_ADDR2BASE(ptr
);
4661 arena
= chunk
->arena
;
4662 assert(arena
->magic
== ARENA_MAGIC
);
4664 if (psize
< oldsize
) {
4666 /* Fill before shrinking in order avoid a race. */
4668 memset((void *)((uintptr_t)ptr
+ size
), 0x5a,
4672 arena_ralloc_large_shrink(arena
, chunk
, ptr
, psize
,
4676 bool ret
= arena_ralloc_large_grow(arena
, chunk
, ptr
,
4679 if (ret
== false && opt_zero
) {
4680 memset((void *)((uintptr_t)ptr
+ oldsize
), 0,
4690 arena_ralloc(void *ptr
, size_t size
, size_t oldsize
)
4695 /* Try to avoid moving the allocation. */
4696 if (size
< small_min
) {
4697 if (oldsize
< small_min
&&
4698 ffs((int)(pow2_ceil(size
) >> (TINY_MIN_2POW
+ 1)))
4699 == ffs((int)(pow2_ceil(oldsize
) >> (TINY_MIN_2POW
+ 1))))
4700 goto IN_PLACE
; /* Same size class. */
4701 } else if (size
<= small_max
) {
4702 if (oldsize
>= small_min
&& oldsize
<= small_max
&&
4703 (QUANTUM_CEILING(size
) >> opt_quantum_2pow
)
4704 == (QUANTUM_CEILING(oldsize
) >> opt_quantum_2pow
))
4705 goto IN_PLACE
; /* Same size class. */
4706 } else if (size
<= bin_maxclass
) {
4707 if (oldsize
> small_max
&& oldsize
<= bin_maxclass
&&
4708 pow2_ceil(size
) == pow2_ceil(oldsize
))
4709 goto IN_PLACE
; /* Same size class. */
4710 } else if (oldsize
> bin_maxclass
&& oldsize
<= arena_maxclass
) {
4711 assert(size
> bin_maxclass
);
4712 if (arena_ralloc_large(ptr
, size
, oldsize
) == false)
4717 * If we get here, then size and oldsize are different enough that we
4718 * need to move the object. In that case, fall back to allocating new
4719 * space and copying.
4721 ret
= arena_malloc(choose_arena(), size
, false);
4725 /* Junk/zero-filling were already done by arena_malloc(). */
4726 copysize
= (size
< oldsize
) ? size
: oldsize
;
4728 if (copysize
>= VM_COPY_MIN
)
4729 pages_copy(ret
, ptr
, copysize
);
4732 memcpy(ret
, ptr
, copysize
);
4737 if (opt_junk
&& size
< oldsize
)
4738 memset((void *)((uintptr_t)ptr
+ size
), 0x5a, oldsize
- size
);
4739 else if (opt_zero
&& size
> oldsize
)
4740 memset((void *)((uintptr_t)ptr
+ oldsize
), 0, size
- oldsize
);
4745 static inline void *
4746 iralloc(void *ptr
, size_t size
)
4750 assert(ptr
!= NULL
);
4753 oldsize
= isalloc(ptr
);
4755 #ifndef MALLOC_VALGRIND
4756 if (size
<= arena_maxclass
)
4757 return (arena_ralloc(ptr
, size
, oldsize
));
4759 return (huge_ralloc(ptr
, size
, oldsize
));
4762 * Valgrind does not provide a public interface for modifying an
4763 * existing allocation, so use malloc/memcpy/free instead.
4766 void *ret
= imalloc(size
);
4769 memcpy(ret
, ptr
, oldsize
);
4771 memcpy(ret
, ptr
, size
);
4780 arena_new(arena_t
*arena
)
4784 size_t pow2_size
, prev_run_size
;
4786 if (malloc_spin_init(&arena
->lock
))
4790 memset(&arena
->stats
, 0, sizeof(arena_stats_t
));
4793 arena
->chunk_seq
= 0;
4795 /* Initialize chunks. */
4796 arena_chunk_tree_dirty_new(&arena
->chunks_dirty
);
4797 arena
->spare
= NULL
;
4801 arena_avail_tree_new(&arena
->runs_avail
);
4803 #ifdef MALLOC_BALANCE
4804 arena
->contention
= 0;
4807 /* Initialize bins. */
4808 prev_run_size
= pagesize
;
4810 /* (2^n)-spaced tiny bins. */
4811 for (i
= 0; i
< ntbins
; i
++) {
4812 bin
= &arena
->bins
[i
];
4814 arena_run_tree_new(&bin
->runs
);
4816 bin
->reg_size
= (1U << (TINY_MIN_2POW
+ i
));
4818 prev_run_size
= arena_bin_run_size_calc(bin
, prev_run_size
);
4821 memset(&bin
->stats
, 0, sizeof(malloc_bin_stats_t
));
4825 /* Quantum-spaced bins. */
4826 for (; i
< ntbins
+ nqbins
; i
++) {
4827 bin
= &arena
->bins
[i
];
4829 arena_run_tree_new(&bin
->runs
);
4831 bin
->reg_size
= quantum
* (i
- ntbins
+ 1);
4833 pow2_size
= pow2_ceil(quantum
* (i
- ntbins
+ 1));
4834 prev_run_size
= arena_bin_run_size_calc(bin
, prev_run_size
);
4837 memset(&bin
->stats
, 0, sizeof(malloc_bin_stats_t
));
4841 /* (2^n)-spaced sub-page bins. */
4842 for (; i
< ntbins
+ nqbins
+ nsbins
; i
++) {
4843 bin
= &arena
->bins
[i
];
4845 arena_run_tree_new(&bin
->runs
);
4847 bin
->reg_size
= (small_max
<< (i
- (ntbins
+ nqbins
) + 1));
4849 prev_run_size
= arena_bin_run_size_calc(bin
, prev_run_size
);
4852 memset(&bin
->stats
, 0, sizeof(malloc_bin_stats_t
));
4857 arena
->magic
= ARENA_MAGIC
;
4863 /* Create a new arena and insert it into the arenas array at index ind. */
4865 arenas_extend(unsigned ind
)
4869 /* Allocate enough space for trailing bins. */
4870 ret
= (arena_t
*)base_alloc(sizeof(arena_t
)
4871 + (sizeof(arena_bin_t
) * (ntbins
+ nqbins
+ nsbins
- 1)));
4872 if (ret
!= NULL
&& arena_new(ret
) == false) {
4876 /* Only reached if there is an OOM error. */
4879 * OOM here is quite inconvenient to propagate, since dealing with it
4880 * would require a check for failure in the fast path. Instead, punt
4881 * by using arenas[0]. In practice, this is an extremely unlikely
4884 _malloc_message(_getprogname(),
4885 ": (malloc) Error initializing arena\n", "", "");
4895 /******************************************************************************/
4897 * Begin general internal functions.
4901 huge_malloc(size_t size
, bool zero
)
4905 #ifdef MALLOC_DECOMMIT
4908 extent_node_t
*node
;
4910 /* Allocate one or more contiguous chunks for this request. */
4912 csize
= CHUNK_CEILING(size
);
4914 /* size is large enough to cause size_t wrap-around. */
4918 /* Allocate an extent node with which to track the chunk. */
4919 node
= base_node_alloc();
4923 ret
= chunk_alloc(csize
, zero
, true);
4925 base_node_dealloc(node
);
4929 /* Insert node into huge. */
4931 #ifdef MALLOC_DECOMMIT
4932 psize
= PAGE_CEILING(size
);
4938 malloc_mutex_lock(&huge_mtx
);
4939 extent_tree_ad_insert(&huge
, node
);
4942 # ifdef MALLOC_DECOMMIT
4943 huge_allocated
+= psize
;
4945 huge_allocated
+= csize
;
4948 malloc_mutex_unlock(&huge_mtx
);
4950 #ifdef MALLOC_DECOMMIT
4951 if (csize
- psize
> 0)
4952 pages_decommit((void *)((uintptr_t)ret
+ psize
), csize
- psize
);
4955 #ifdef MALLOC_DECOMMIT
4956 VALGRIND_MALLOCLIKE_BLOCK(ret
, psize
, 0, zero
);
4958 VALGRIND_MALLOCLIKE_BLOCK(ret
, csize
, 0, zero
);
4962 if (zero
== false) {
4964 # ifdef MALLOC_DECOMMIT
4965 memset(ret
, 0xa5, psize
);
4967 memset(ret
, 0xa5, csize
);
4970 # ifdef MALLOC_DECOMMIT
4971 memset(ret
, 0, psize
);
4973 memset(ret
, 0, csize
);
4981 /* Only handles large allocations that require more than chunk alignment. */
4983 huge_palloc(size_t alignment
, size_t size
)
4986 size_t alloc_size
, chunk_size
, offset
;
4987 #ifdef MALLOC_DECOMMIT
4990 extent_node_t
*node
;
4994 * This allocation requires alignment that is even larger than chunk
4995 * alignment. This means that huge_malloc() isn't good enough.
4997 * Allocate almost twice as many chunks as are demanded by the size or
4998 * alignment, in order to assure the alignment can be achieved, then
4999 * unmap leading and trailing chunks.
5001 assert(alignment
>= chunksize
);
5003 chunk_size
= CHUNK_CEILING(size
);
5005 if (size
>= alignment
)
5006 alloc_size
= chunk_size
+ alignment
- chunksize
;
5008 alloc_size
= (alignment
<< 1) - chunksize
;
5010 /* Allocate an extent node with which to track the chunk. */
5011 node
= base_node_alloc();
5016 * Windows requires that there be a 1:1 mapping between VM
5017 * allocation/deallocation operations. Therefore, take care here to
5018 * acquire the final result via one mapping operation.
5020 * The MALLOC_PAGEFILE code also benefits from this mapping algorithm,
5021 * since it reduces the number of page files.
5023 #ifdef MALLOC_PAGEFILE
5025 pfd
= pagefile_init(size
);
5031 #ifdef JEMALLOC_USES_MAP_ALIGN
5032 ret
= pages_map_align(chunk_size
, pfd
, alignment
);
5037 over
= chunk_alloc(alloc_size
, false, false);
5039 base_node_dealloc(node
);
5044 offset
= (uintptr_t)over
& (alignment
- 1);
5045 assert((offset
& chunksize_mask
) == 0);
5046 assert(offset
< alloc_size
);
5047 ret
= (void *)((uintptr_t)over
+ offset
);
5048 chunk_dealloc(over
, alloc_size
);
5049 ret
= pages_map(ret
, chunk_size
, pfd
);
5051 * Failure here indicates a race with another thread, so try
5054 } while (ret
== NULL
);
5056 /* Insert node into huge. */
5058 #ifdef MALLOC_DECOMMIT
5059 psize
= PAGE_CEILING(size
);
5062 node
->size
= chunk_size
;
5065 malloc_mutex_lock(&huge_mtx
);
5066 extent_tree_ad_insert(&huge
, node
);
5069 # ifdef MALLOC_DECOMMIT
5070 huge_allocated
+= psize
;
5072 huge_allocated
+= chunk_size
;
5075 malloc_mutex_unlock(&huge_mtx
);
5077 #ifdef MALLOC_DECOMMIT
5078 if (chunk_size
- psize
> 0) {
5079 pages_decommit((void *)((uintptr_t)ret
+ psize
),
5080 chunk_size
- psize
);
5084 #ifdef MALLOC_DECOMMIT
5085 VALGRIND_MALLOCLIKE_BLOCK(ret
, psize
, 0, false);
5087 VALGRIND_MALLOCLIKE_BLOCK(ret
, chunk_size
, 0, false);
5092 # ifdef MALLOC_DECOMMIT
5093 memset(ret
, 0xa5, psize
);
5095 memset(ret
, 0xa5, chunk_size
);
5098 # ifdef MALLOC_DECOMMIT
5099 memset(ret
, 0, psize
);
5101 memset(ret
, 0, chunk_size
);
5106 #ifdef MALLOC_PAGEFILE
5108 pagefile_close(pfd
);
5114 huge_ralloc(void *ptr
, size_t size
, size_t oldsize
)
5119 /* Avoid moving the allocation if the size class would not change. */
5121 if (oldsize
> arena_maxclass
&&
5122 CHUNK_CEILING(size
) == CHUNK_CEILING(oldsize
)) {
5123 #ifdef MALLOC_DECOMMIT
5124 size_t psize
= PAGE_CEILING(size
);
5127 if (opt_junk
&& size
< oldsize
) {
5128 memset((void *)((uintptr_t)ptr
+ size
), 0x5a, oldsize
5132 #ifdef MALLOC_DECOMMIT
5133 if (psize
< oldsize
) {
5134 extent_node_t
*node
, key
;
5136 pages_decommit((void *)((uintptr_t)ptr
+ psize
),
5139 /* Update recorded size. */
5140 malloc_mutex_lock(&huge_mtx
);
5141 key
.addr
= __DECONST(void *, ptr
);
5142 node
= extent_tree_ad_search(&huge
, &key
);
5143 assert(node
!= NULL
);
5144 assert(node
->size
== oldsize
);
5145 # ifdef MALLOC_STATS
5146 huge_allocated
-= oldsize
- psize
;
5149 malloc_mutex_unlock(&huge_mtx
);
5150 } else if (psize
> oldsize
) {
5151 extent_node_t
*node
, key
;
5153 pages_commit((void *)((uintptr_t)ptr
+ oldsize
),
5156 /* Update recorded size. */
5157 malloc_mutex_lock(&huge_mtx
);
5158 key
.addr
= __DECONST(void *, ptr
);
5159 node
= extent_tree_ad_search(&huge
, &key
);
5160 assert(node
!= NULL
);
5161 assert(node
->size
== oldsize
);
5162 # ifdef MALLOC_STATS
5163 huge_allocated
+= psize
- oldsize
;
5166 malloc_mutex_unlock(&huge_mtx
);
5170 if (opt_zero
&& size
> oldsize
) {
5171 memset((void *)((uintptr_t)ptr
+ oldsize
), 0, size
5179 * If we get here, then size and oldsize are different enough that we
5180 * need to use a different size class. In that case, fall back to
5181 * allocating new space and copying.
5183 ret
= huge_malloc(size
, false);
5187 copysize
= (size
< oldsize
) ? size
: oldsize
;
5189 if (copysize
>= VM_COPY_MIN
)
5190 pages_copy(ret
, ptr
, copysize
);
5193 memcpy(ret
, ptr
, copysize
);
5199 huge_dalloc(void *ptr
)
5201 extent_node_t
*node
, key
;
5203 malloc_mutex_lock(&huge_mtx
);
5205 /* Extract from tree of huge allocations. */
5207 node
= extent_tree_ad_search(&huge
, &key
);
5208 assert(node
!= NULL
);
5209 assert(node
->addr
== ptr
);
5210 extent_tree_ad_remove(&huge
, node
);
5214 huge_allocated
-= node
->size
;
5217 malloc_mutex_unlock(&huge_mtx
);
5222 memset(node
->addr
, 0x5a, node
->size
);
5224 #ifdef MALLOC_DECOMMIT
5225 chunk_dealloc(node
->addr
, CHUNK_CEILING(node
->size
));
5227 chunk_dealloc(node
->addr
, node
->size
);
5229 VALGRIND_FREELIKE_BLOCK(node
->addr
, 0);
5231 base_node_dealloc(node
);
5234 #ifdef MOZ_MEMORY_BSD
5235 static inline unsigned
5245 if (sysctl(mib
, 2, &ret
, &len
, (void *) 0, 0) == -1) {
5252 #elif (defined(MOZ_MEMORY_LINUX))
5255 static inline unsigned
5259 int fd
, nread
, column
;
5261 static const char matchstr
[] = "processor\t:";
5265 * sysconf(3) would be the preferred method for determining the number
5266 * of CPUs, but it uses malloc internally, which causes untennable
5267 * recursion during malloc initialization.
5269 fd
= open("/proc/cpuinfo", O_RDONLY
);
5271 return (1); /* Error. */
5273 * Count the number of occurrences of matchstr at the beginnings of
5274 * lines. This treats hyperthreaded CPUs as multiple processors.
5279 nread
= read(fd
, &buf
, sizeof(buf
));
5281 break; /* EOF or error. */
5282 for (i
= 0;i
< nread
;i
++) {
5286 else if (column
!= -1) {
5287 if (c
== matchstr
[column
]) {
5289 if (column
== sizeof(matchstr
) - 1) {
5300 ret
= 1; /* Something went wrong in the parser. */
5305 #elif (defined(MOZ_MEMORY_DARWIN))
5306 #include <mach/mach_init.h>
5307 #include <mach/mach_host.h>
5309 static inline unsigned
5312 kern_return_t error
;
5314 processor_info_array_t pinfo
;
5315 mach_msg_type_number_t pinfocnt
;
5317 error
= host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO
,
5318 &n
, &pinfo
, &pinfocnt
);
5319 if (error
!= KERN_SUCCESS
)
5320 return (1); /* Error. */
5324 #elif (defined(MOZ_MEMORY_SOLARIS))
5326 static inline unsigned
5329 return sysconf(_SC_NPROCESSORS_ONLN
);
5332 static inline unsigned
5337 * We lack a way to determine the number of CPUs on this platform, so
5345 malloc_print_stats(void)
5348 if (opt_print_stats
) {
5349 char s
[UMAX2S_BUFSIZE
];
5350 _malloc_message("___ Begin malloc statistics ___\n", "", "",
5352 _malloc_message("Assertions ",
5359 _malloc_message("Boolean MALLOC_OPTIONS: ",
5360 opt_abort
? "A" : "a", "", "");
5362 _malloc_message(opt_junk
? "J" : "j", "", "", "");
5364 #ifdef MALLOC_PAGEFILE
5365 _malloc_message(opt_pagefile
? "o" : "O", "", "", "");
5367 _malloc_message("P", "", "", "");
5368 #ifdef MALLOC_UTRACE
5369 _malloc_message(opt_utrace
? "U" : "u", "", "", "");
5372 _malloc_message(opt_sysv
? "V" : "v", "", "", "");
5374 #ifdef MALLOC_XMALLOC
5375 _malloc_message(opt_xmalloc
? "X" : "x", "", "", "");
5378 _malloc_message(opt_zero
? "Z" : "z", "", "", "");
5380 _malloc_message("\n", "", "", "");
5382 _malloc_message("CPUs: ", umax2s(ncpus
, s
), "\n", "");
5383 _malloc_message("Max arenas: ", umax2s(narenas
, s
), "\n", "");
5384 #ifdef MALLOC_BALANCE
5385 _malloc_message("Arena balance threshold: ",
5386 umax2s(opt_balance_threshold
, s
), "\n", "");
5388 _malloc_message("Pointer size: ", umax2s(sizeof(void *), s
),
5390 _malloc_message("Quantum size: ", umax2s(quantum
, s
), "\n", "");
5391 _malloc_message("Max small size: ", umax2s(small_max
, s
), "\n",
5393 _malloc_message("Max dirty pages per arena: ",
5394 umax2s(opt_dirty_max
, s
), "\n", "");
5396 _malloc_message("Chunk size: ", umax2s(chunksize
, s
), "", "");
5397 _malloc_message(" (2^", umax2s(opt_chunk_2pow
, s
), ")\n", "");
5401 size_t allocated
, mapped
;
5402 #ifdef MALLOC_BALANCE
5403 uint64_t nbalance
= 0;
5408 /* Calculate and print allocated/mapped stats. */
5411 for (i
= 0, allocated
= 0; i
< narenas
; i
++) {
5412 if (arenas
[i
] != NULL
) {
5413 malloc_spin_lock(&arenas
[i
]->lock
);
5415 arenas
[i
]->stats
.allocated_small
;
5417 arenas
[i
]->stats
.allocated_large
;
5418 #ifdef MALLOC_BALANCE
5419 nbalance
+= arenas
[i
]->stats
.nbalance
;
5421 malloc_spin_unlock(&arenas
[i
]->lock
);
5426 malloc_mutex_lock(&huge_mtx
);
5427 allocated
+= huge_allocated
;
5428 mapped
= stats_chunks
.curchunks
* chunksize
;
5429 malloc_mutex_unlock(&huge_mtx
);
5431 malloc_mutex_lock(&base_mtx
);
5432 mapped
+= base_mapped
;
5433 malloc_mutex_unlock(&base_mtx
);
5435 #ifdef MOZ_MEMORY_WINDOWS
5436 malloc_printf("Allocated: %lu, mapped: %lu\n",
5439 malloc_printf("Allocated: %zu, mapped: %zu\n",
5443 malloc_mutex_lock(&reserve_mtx
);
5444 malloc_printf("Reserve: min "
5446 #ifdef MOZ_MEMORY_WINDOWS
5447 malloc_printf(" %12lu %12lu %12lu\n",
5448 CHUNK_CEILING(reserve_min
) >> opt_chunk_2pow
,
5449 reserve_cur
>> opt_chunk_2pow
,
5450 reserve_max
>> opt_chunk_2pow
);
5452 malloc_printf(" %12zu %12zu %12zu\n",
5453 CHUNK_CEILING(reserve_min
) >> opt_chunk_2pow
,
5454 reserve_cur
>> opt_chunk_2pow
,
5455 reserve_max
>> opt_chunk_2pow
);
5457 malloc_mutex_unlock(&reserve_mtx
);
5459 #ifdef MALLOC_BALANCE
5460 malloc_printf("Arena balance reassignments: %llu\n",
5464 /* Print chunk stats. */
5466 chunk_stats_t chunks_stats
;
5468 malloc_mutex_lock(&huge_mtx
);
5469 chunks_stats
= stats_chunks
;
5470 malloc_mutex_unlock(&huge_mtx
);
5472 malloc_printf("chunks: nchunks "
5473 "highchunks curchunks\n");
5474 malloc_printf(" %13llu%13lu%13lu\n",
5475 chunks_stats
.nchunks
,
5476 chunks_stats
.highchunks
,
5477 chunks_stats
.curchunks
);
5480 /* Print chunk stats. */
5482 "huge: nmalloc ndalloc allocated\n");
5483 #ifdef MOZ_MEMORY_WINDOWS
5484 malloc_printf(" %12llu %12llu %12lu\n",
5485 huge_nmalloc
, huge_ndalloc
, huge_allocated
);
5487 malloc_printf(" %12llu %12llu %12zu\n",
5488 huge_nmalloc
, huge_ndalloc
, huge_allocated
);
5490 /* Print stats for each arena. */
5491 for (i
= 0; i
< narenas
; i
++) {
5493 if (arena
!= NULL
) {
5495 "\narenas[%u]:\n", i
);
5496 malloc_spin_lock(&arena
->lock
);
5498 malloc_spin_unlock(&arena
->lock
);
5502 #endif /* #ifdef MALLOC_STATS */
5503 _malloc_message("--- End malloc statistics ---\n", "", "", "");
5508 * FreeBSD's pthreads implementation calls malloc(3), so the malloc
5509 * implementation has to take pains to avoid infinite recursion during
5512 #if (defined(MOZ_MEMORY_WINDOWS) || defined(MOZ_MEMORY_DARWIN)) && !defined(MOZ_MEMORY_WINCE)
5513 #define malloc_init() false
5519 if (malloc_initialized
== false)
5520 return (malloc_init_hard());
5526 #if !defined(MOZ_MEMORY_WINDOWS) || defined(MOZ_MEMORY_WINCE)
5530 malloc_init_hard(void)
5533 char buf
[PATH_MAX
+ 1];
5536 #ifndef MOZ_MEMORY_WINDOWS
5540 #ifndef MOZ_MEMORY_WINDOWS
5541 malloc_mutex_lock(&init_lock
);
5544 if (malloc_initialized
) {
5546 * Another thread initialized the allocator before this one
5547 * acquired init_lock.
5549 #ifndef MOZ_MEMORY_WINDOWS
5550 malloc_mutex_unlock(&init_lock
);
5555 #ifdef MOZ_MEMORY_WINDOWS
5556 /* get a thread local storage index */
5557 tlsIndex
= TlsAlloc();
5560 /* Get page size and number of CPUs */
5561 #ifdef MOZ_MEMORY_WINDOWS
5565 GetSystemInfo(&info
);
5566 result
= info
.dwPageSize
;
5568 pagesize
= (unsigned) result
;
5570 ncpus
= info
.dwNumberOfProcessors
;
5573 ncpus
= malloc_ncpus();
5575 result
= sysconf(_SC_PAGESIZE
);
5576 assert(result
!= -1);
5578 pagesize
= (unsigned) result
;
5582 * We assume that pagesize is a power of 2 when calculating
5583 * pagesize_mask and pagesize_2pow.
5585 assert(((result
- 1) & result
) == 0);
5586 pagesize_mask
= result
- 1;
5587 pagesize_2pow
= ffs((int)result
) - 1;
5589 #ifdef MALLOC_PAGEFILE
5591 * Determine where to create page files. It is insufficient to
5592 * unconditionally use P_tmpdir (typically "/tmp"), since for some
5593 * operating systems /tmp is a separate filesystem that is rather small.
5594 * Therefore prefer, in order, the following locations:
5603 static const char suffix
[] = "/jemalloc.XXXXXX";
5605 if ((s
= getenv("MALLOC_TMPDIR")) == NULL
&& (s
=
5606 getenv("TMPDIR")) == NULL
)
5609 if (slen
+ sizeof(suffix
) > sizeof(pagefile_templ
)) {
5610 _malloc_message(_getprogname(),
5611 ": (malloc) Page file path too long\n",
5615 memcpy(pagefile_templ
, s
, slen
);
5616 memcpy(&pagefile_templ
[slen
], suffix
, sizeof(suffix
));
5620 for (i
= 0; i
< 3; i
++) {
5623 /* Get runtime configuration. */
5626 #ifndef MOZ_MEMORY_WINDOWS
5627 if ((linklen
= readlink("/etc/malloc.conf", buf
,
5628 sizeof(buf
) - 1)) != -1) {
5630 * Use the contents of the "/etc/malloc.conf"
5631 * symbolic link's name.
5633 buf
[linklen
] = '\0';
5638 /* No configuration specified. */
5644 if (issetugid() == 0 && (opts
=
5645 getenv("MALLOC_OPTIONS")) != NULL
) {
5647 * Do nothing; opts is already initialized to
5648 * the value of the MALLOC_OPTIONS environment
5652 /* No configuration specified. */
5658 if (_malloc_options
!= NULL
) {
5660 * Use options that were compiled into the
5663 opts
= _malloc_options
;
5665 /* No configuration specified. */
5677 for (j
= 0; opts
[j
] != '\0'; j
++) {
5681 /* Parse repetition count, if any. */
5682 for (nreps
= 0, nseen
= false;; j
++, nseen
= true) {
5684 case '0': case '1': case '2': case '3':
5685 case '4': case '5': case '6': case '7':
5688 nreps
+= opts
[j
] - '0';
5698 for (k
= 0; k
< nreps
; k
++) {
5707 #ifdef MALLOC_BALANCE
5708 opt_balance_threshold
>>= 1;
5712 #ifdef MALLOC_BALANCE
5713 if (opt_balance_threshold
== 0)
5714 opt_balance_threshold
= 1;
5715 else if ((opt_balance_threshold
<< 1)
5716 > opt_balance_threshold
)
5717 opt_balance_threshold
<<= 1;
5721 opt_dirty_max
>>= 1;
5724 if (opt_dirty_max
== 0)
5726 else if ((opt_dirty_max
<< 1) != 0)
5727 opt_dirty_max
<<= 1;
5730 opt_reserve_range_lshift
--;
5733 opt_reserve_range_lshift
++;
5745 * Chunks always require at least one
5746 * header page, so chunks can never be
5747 * smaller than two pages.
5749 if (opt_chunk_2pow
> pagesize_2pow
+ 1)
5753 if (opt_chunk_2pow
+ 1 <
5754 (sizeof(size_t) << 3))
5758 opt_narenas_lshift
--;
5761 opt_narenas_lshift
++;
5763 #ifdef MALLOC_PAGEFILE
5765 /* Do not over-commit. */
5766 opt_pagefile
= true;
5769 /* Allow over-commit. */
5770 opt_pagefile
= false;
5774 opt_print_stats
= false;
5777 opt_print_stats
= true;
5780 if (opt_quantum_2pow
> QUANTUM_2POW_MIN
)
5784 if (opt_quantum_2pow
< pagesize_2pow
-
5789 opt_reserve_min_lshift
--;
5792 opt_reserve_min_lshift
++;
5795 if (opt_small_max_2pow
>
5797 opt_small_max_2pow
--;
5800 if (opt_small_max_2pow
< pagesize_2pow
5802 opt_small_max_2pow
++;
5804 #ifdef MALLOC_UTRACE
5820 #ifdef MALLOC_XMALLOC
5822 opt_xmalloc
= false;
5841 _malloc_message(_getprogname(),
5842 ": (malloc) Unsupported character "
5843 "in malloc options: '", cbuf
,
5851 /* Take care to call atexit() only once. */
5852 if (opt_print_stats
) {
5853 #ifndef MOZ_MEMORY_WINDOWS
5854 /* Print statistics at exit. */
5855 atexit(malloc_print_stats
);
5859 #if (!defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN))
5860 /* Prevent potential deadlock on malloc locks after fork. */
5861 pthread_atfork(_malloc_prefork
, _malloc_postfork
, _malloc_postfork
);
5864 /* Set variables according to the value of opt_small_max_2pow. */
5865 if (opt_small_max_2pow
< opt_quantum_2pow
)
5866 opt_small_max_2pow
= opt_quantum_2pow
;
5867 small_max
= (1U << opt_small_max_2pow
);
5869 /* Set bin-related variables. */
5870 bin_maxclass
= (pagesize
>> 1);
5871 assert(opt_quantum_2pow
>= TINY_MIN_2POW
);
5872 ntbins
= opt_quantum_2pow
- TINY_MIN_2POW
;
5873 assert(ntbins
<= opt_quantum_2pow
);
5874 nqbins
= (small_max
>> opt_quantum_2pow
);
5875 nsbins
= pagesize_2pow
- opt_small_max_2pow
- 1;
5877 /* Set variables according to the value of opt_quantum_2pow. */
5878 quantum
= (1U << opt_quantum_2pow
);
5879 quantum_mask
= quantum
- 1;
5881 small_min
= (quantum
>> 1) + 1;
5884 assert(small_min
<= quantum
);
5886 /* Set variables according to the value of opt_chunk_2pow. */
5887 chunksize
= (1LU << opt_chunk_2pow
);
5888 chunksize_mask
= chunksize
- 1;
5889 chunk_npages
= (chunksize
>> pagesize_2pow
);
5894 * Compute the header size such that it is large
5895 * enough to contain the page map and enough nodes for the
5896 * worst case: one node per non-header page plus one extra for
5897 * situations where we briefly have one more node allocated
5898 * than we will need.
5900 header_size
= sizeof(arena_chunk_t
) +
5901 (sizeof(arena_chunk_map_t
) * (chunk_npages
- 1));
5902 arena_chunk_header_npages
= (header_size
>> pagesize_2pow
) +
5903 ((header_size
& pagesize_mask
) != 0);
5905 arena_maxclass
= chunksize
- (arena_chunk_header_npages
<<
5908 #ifdef JEMALLOC_USES_MAP_ALIGN
5910 * When using MAP_ALIGN, the alignment parameter must be a power of two
5911 * multiple of the system pagesize, or mmap will fail.
5913 assert((chunksize
% pagesize
) == 0);
5914 assert((1 << (ffs(chunksize
/ pagesize
) - 1)) == (chunksize
/pagesize
));
5920 memset(&stats_chunks
, 0, sizeof(chunk_stats_t
));
5923 /* Various sanity checks that regard configuration. */
5924 assert(quantum
>= sizeof(void *));
5925 assert(quantum
<= pagesize
);
5926 assert(chunksize
>= pagesize
);
5927 assert(quantum
* 4 <= chunksize
);
5929 /* Initialize chunks data. */
5930 malloc_mutex_init(&huge_mtx
);
5931 extent_tree_ad_new(&huge
);
5938 /* Initialize base allocation data structures. */
5943 base_reserve_regs
= NULL
;
5944 malloc_mutex_init(&base_mtx
);
5946 #ifdef MOZ_MEMORY_NARENAS_DEFAULT_ONE
5951 * For SMP systems, create four times as many arenas as there
5952 * are CPUs by default.
5954 opt_narenas_lshift
+= 2;
5957 /* Determine how many arenas to use. */
5960 if (opt_narenas_lshift
> 0) {
5961 if ((narenas
<< opt_narenas_lshift
) > narenas
)
5962 narenas
<<= opt_narenas_lshift
;
5964 * Make sure not to exceed the limits of what base_alloc() can
5967 if (narenas
* sizeof(arena_t
*) > chunksize
)
5968 narenas
= chunksize
/ sizeof(arena_t
*);
5969 } else if (opt_narenas_lshift
< 0) {
5970 if ((narenas
>> -opt_narenas_lshift
) < narenas
)
5971 narenas
>>= -opt_narenas_lshift
;
5972 /* Make sure there is at least one arena. */
5976 #ifdef MALLOC_BALANCE
5977 assert(narenas
!= 0);
5978 for (narenas_2pow
= 0;
5979 (narenas
>> (narenas_2pow
+ 1)) != 0;
5985 static const unsigned primes
[] = {1, 3, 5, 7, 11, 13, 17, 19,
5986 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
5987 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
5988 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
5989 223, 227, 229, 233, 239, 241, 251, 257, 263};
5990 unsigned nprimes
, parenas
;
5993 * Pick a prime number of hash arenas that is more than narenas
5994 * so that direct hashing of pthread_self() pointers tends to
5995 * spread allocations evenly among the arenas.
5997 assert((narenas
& 1) == 0); /* narenas must be even. */
5998 nprimes
= (sizeof(primes
) >> SIZEOF_INT_2POW
);
5999 parenas
= primes
[nprimes
- 1]; /* In case not enough primes. */
6000 for (i
= 1; i
< nprimes
; i
++) {
6001 if (primes
[i
] > narenas
) {
6002 parenas
= primes
[i
];
6011 # ifndef MALLOC_BALANCE
6016 /* Allocate and initialize arenas. */
6017 arenas
= (arena_t
**)base_alloc(sizeof(arena_t
*) * narenas
);
6018 if (arenas
== NULL
) {
6019 #ifndef MOZ_MEMORY_WINDOWS
6020 malloc_mutex_unlock(&init_lock
);
6025 * Zero the array. In practice, this should always be pre-zeroed,
6026 * since it was just mmap()ed, but let's be sure.
6028 memset(arenas
, 0, sizeof(arena_t
*) * narenas
);
6031 * Initialize one arena here. The rest are lazily created in
6032 * choose_arena_hard().
6035 if (arenas
[0] == NULL
) {
6036 #ifndef MOZ_MEMORY_WINDOWS
6037 malloc_mutex_unlock(&init_lock
);
6043 * Assign the initial arena to the initial thread, in order to avoid
6044 * spurious creation of an extra arena if the application switches to
6047 #ifdef MOZ_MEMORY_WINDOWS
6048 TlsSetValue(tlsIndex
, arenas
[0]);
6050 arenas_map
= arenas
[0];
6055 * Seed here for the initial thread, since choose_arena_hard() is only
6056 * called for other threads. The seed value doesn't really matter.
6058 #ifdef MALLOC_BALANCE
6062 malloc_spin_init(&arenas_lock
);
6064 #ifdef MALLOC_VALIDATE
6065 chunk_rtree
= malloc_rtree_new((SIZEOF_PTR
<< 3) - opt_chunk_2pow
);
6066 if (chunk_rtree
== NULL
)
6071 * Configure and initialize the memory reserve. This needs to happen
6072 * late during initialization, since chunks are allocated.
6074 malloc_mutex_init(&reserve_mtx
);
6078 if (RESERVE_RANGE_2POW_DEFAULT
+ opt_reserve_range_lshift
>= 0) {
6079 reserve_max
+= chunksize
<< (RESERVE_RANGE_2POW_DEFAULT
+
6080 opt_reserve_range_lshift
);
6082 ql_new(&reserve_regs
);
6084 extent_tree_szad_new(&reserve_chunks_szad
);
6085 extent_tree_ad_new(&reserve_chunks_ad
);
6086 if (RESERVE_MIN_2POW_DEFAULT
+ opt_reserve_min_lshift
>= 0) {
6087 reserve_min_set(chunksize
<< (RESERVE_MIN_2POW_DEFAULT
+
6088 opt_reserve_min_lshift
));
6091 malloc_initialized
= true;
6092 #ifndef MOZ_MEMORY_WINDOWS
6093 malloc_mutex_unlock(&init_lock
);
6098 /* XXX Why not just expose malloc_print_stats()? */
6099 #ifdef MOZ_MEMORY_WINDOWS
6104 malloc_print_stats();
6109 * End general internal functions.
6111 /******************************************************************************/
6113 * Begin malloc(3)-compatible functions.
6117 * Inline the standard malloc functions if they are being subsumed by Darwin's
6118 * zone infrastructure.
6120 #ifdef MOZ_MEMORY_DARWIN
6121 # define ZONE_INLINE inline
6123 # define ZONE_INLINE
6126 /* Mangle standard interfaces on Darwin and Windows CE,
6127 in order to avoid linking problems. */
6128 #if defined(MOZ_MEMORY_DARWIN)
6129 #define malloc(a) moz_malloc(a)
6130 #define valloc(a) moz_valloc(a)
6131 #define calloc(a, b) moz_calloc(a, b)
6132 #define realloc(a, b) moz_realloc(a, b)
6133 #define free(a) moz_free(a)
6142 if (malloc_init()) {
6149 if (opt_sysv
== false)
6160 ret
= imalloc(size
);
6164 #ifdef MALLOC_XMALLOC
6166 _malloc_message(_getprogname(),
6167 ": (malloc) Error in malloc(): out of memory\n", "",
6175 UTRACE(0, size
, ret
);
6179 #ifdef MOZ_MEMORY_SOLARIS
6182 memalign(size_t alignment
, size_t size
);
6183 #pragma no_inline(memalign)
6184 # elif (defined(__GNU_C__))
6185 __attribute__((noinline
))
6191 memalign(size_t alignment
, size_t size
)
6195 assert(((alignment
- 1) & alignment
) == 0 && alignment
>=
6198 if (malloc_init()) {
6203 ret
= ipalloc(alignment
, size
);
6206 #ifdef MALLOC_XMALLOC
6207 if (opt_xmalloc
&& ret
== NULL
) {
6208 _malloc_message(_getprogname(),
6209 ": (malloc) Error in memalign(): out of memory\n", "", "");
6213 UTRACE(0, size
, ret
);
6219 posix_memalign(void **memptr
, size_t alignment
, size_t size
)
6223 /* Make sure that alignment is a large enough power of 2. */
6224 if (((alignment
- 1) & alignment
) != 0 || alignment
< sizeof(void *)) {
6225 #ifdef MALLOC_XMALLOC
6227 _malloc_message(_getprogname(),
6228 ": (malloc) Error in posix_memalign(): "
6229 "invalid alignment\n", "", "");
6236 #ifdef MOZ_MEMORY_DARWIN
6237 result
= moz_memalign(alignment
, size
);
6239 result
= memalign(alignment
, size
);
6252 #ifdef MOZ_MEMORY_DARWIN
6253 return (moz_memalign(pagesize
, size
));
6255 return (memalign(pagesize
, size
));
6261 calloc(size_t num
, size_t size
)
6266 if (malloc_init()) {
6272 num_size
= num
* size
;
6273 if (num_size
== 0) {
6275 if ((opt_sysv
== false) && ((num
== 0) || (size
== 0)))
6285 * Try to avoid division here. We know that it isn't possible to
6286 * overflow during multiplication if neither operand uses any of the
6287 * most significant half of the bits in a size_t.
6289 } else if (((num
| size
) & (SIZE_T_MAX
<< (sizeof(size_t) << 2)))
6290 && (num_size
/ size
!= num
)) {
6291 /* size_t overflow. */
6296 ret
= icalloc(num_size
);
6300 #ifdef MALLOC_XMALLOC
6302 _malloc_message(_getprogname(),
6303 ": (malloc) Error in calloc(): out of memory\n", "",
6311 UTRACE(0, num_size
, ret
);
6317 realloc(void *ptr
, size_t size
)
6323 if (opt_sysv
== false)
6337 assert(malloc_initialized
);
6339 ret
= iralloc(ptr
, size
);
6342 #ifdef MALLOC_XMALLOC
6344 _malloc_message(_getprogname(),
6345 ": (malloc) Error in realloc(): out of "
6346 "memory\n", "", "");
6356 ret
= imalloc(size
);
6359 #ifdef MALLOC_XMALLOC
6361 _malloc_message(_getprogname(),
6362 ": (malloc) Error in realloc(): out of "
6363 "memory\n", "", "");
6374 UTRACE(ptr
, size
, ret
);
6385 assert(malloc_initialized
);
6392 * End malloc(3)-compatible functions.
6394 /******************************************************************************/
6396 * Begin non-standard functions.
6400 malloc_usable_size(const void *ptr
)
6403 #ifdef MALLOC_VALIDATE
6404 return (isalloc_validate(ptr
));
6406 assert(ptr
!= NULL
);
6408 return (isalloc(ptr
));
6413 jemalloc_stats(jemalloc_stats_t
*stats
)
6417 assert(stats
!= NULL
);
6420 * Gather runtime settings.
6422 stats
->opt_abort
= opt_abort
;
6429 #ifdef MALLOC_UTRACE
6438 stats
->opt_xmalloc
=
6439 #ifdef MALLOC_XMALLOC
6440 opt_xmalloc
? true :
6448 stats
->narenas
= narenas
;
6449 stats
->balance_threshold
=
6450 #ifdef MALLOC_BALANCE
6451 opt_balance_threshold
6456 stats
->quantum
= quantum
;
6457 stats
->small_max
= small_max
;
6458 stats
->large_max
= arena_maxclass
;
6459 stats
->chunksize
= chunksize
;
6460 stats
->dirty_max
= opt_dirty_max
;
6462 malloc_mutex_lock(&reserve_mtx
);
6463 stats
->reserve_min
= reserve_min
;
6464 stats
->reserve_max
= reserve_max
;
6465 stats
->reserve_cur
= reserve_cur
;
6466 malloc_mutex_unlock(&reserve_mtx
);
6469 * Gather current memory usage statistics.
6472 stats
->committed
= 0;
6473 stats
->allocated
= 0;
6476 /* Get huge mapped/allocated. */
6477 malloc_mutex_lock(&huge_mtx
);
6478 stats
->mapped
+= stats_chunks
.curchunks
* chunksize
;
6479 #ifdef MALLOC_DECOMMIT
6480 stats
->committed
+= huge_allocated
;
6482 stats
->allocated
+= huge_allocated
;
6483 malloc_mutex_unlock(&huge_mtx
);
6485 /* Get base mapped. */
6486 malloc_mutex_lock(&base_mtx
);
6487 stats
->mapped
+= base_mapped
;
6488 #ifdef MALLOC_DECOMMIT
6489 stats
->committed
+= base_mapped
;
6491 malloc_mutex_unlock(&base_mtx
);
6493 /* Iterate over arenas and their chunks. */
6494 for (i
= 0; i
< narenas
; i
++) {
6495 arena_t
*arena
= arenas
[i
];
6496 if (arena
!= NULL
) {
6497 arena_chunk_t
*chunk
;
6499 malloc_spin_lock(&arena
->lock
);
6500 stats
->allocated
+= arena
->stats
.allocated_small
;
6501 stats
->allocated
+= arena
->stats
.allocated_large
;
6502 #ifdef MALLOC_DECOMMIT
6503 rb_foreach_begin(arena_chunk_t
, link_dirty
,
6504 &arena
->chunks_dirty
, chunk
) {
6507 for (j
= 0; j
< chunk_npages
; j
++) {
6508 if ((chunk
->map
[j
].bits
&
6509 CHUNK_MAP_DECOMMITTED
) == 0)
6510 stats
->committed
+= pagesize
;
6512 } rb_foreach_end(arena_chunk_t
, link_dirty
,
6513 &arena
->chunks_dirty
, chunk
)
6515 stats
->dirty
+= (arena
->ndirty
<< pagesize_2pow
);
6516 malloc_spin_unlock(&arena
->lock
);
6520 #ifndef MALLOC_DECOMMIT
6521 stats
->committed
= stats
->mapped
;
6526 xmalloc(size_t size
)
6531 reserve_fail(size
, "xmalloc");
6535 if (opt_sysv
== false)
6540 _malloc_message(_getprogname(),
6541 ": (malloc) Error in xmalloc(): ",
6542 "invalid size 0", "\n");
6548 ret
= imalloc(size
);
6553 seq
= reserve_crit(size
, "xmalloc", seq
);
6554 ret
= imalloc(size
);
6555 } while (ret
== NULL
);
6558 UTRACE(0, size
, ret
);
6563 xcalloc(size_t num
, size_t size
)
6568 num_size
= num
* size
;
6570 reserve_fail(num_size
, "xcalloc");
6572 if (num_size
== 0) {
6574 if ((opt_sysv
== false) && ((num
== 0) || (size
== 0)))
6579 _malloc_message(_getprogname(),
6580 ": (malloc) Error in xcalloc(): ",
6581 "invalid size 0", "\n");
6586 * Try to avoid division here. We know that it isn't possible to
6587 * overflow during multiplication if neither operand uses any of the
6588 * most significant half of the bits in a size_t.
6590 } else if (((num
| size
) & (SIZE_T_MAX
<< (sizeof(size_t) << 2)))
6591 && (num_size
/ size
!= num
)) {
6592 /* size_t overflow. */
6593 _malloc_message(_getprogname(),
6594 ": (malloc) Error in xcalloc(): ",
6595 "size overflow", "\n");
6599 ret
= icalloc(num_size
);
6604 seq
= reserve_crit(num_size
, "xcalloc", seq
);
6605 ret
= icalloc(num_size
);
6606 } while (ret
== NULL
);
6609 UTRACE(0, num_size
, ret
);
6614 xrealloc(void *ptr
, size_t size
)
6620 if (opt_sysv
== false)
6627 _malloc_message(_getprogname(),
6628 ": (malloc) Error in xrealloc(): ",
6629 "invalid size 0", "\n");
6636 assert(malloc_initialized
);
6638 ret
= iralloc(ptr
, size
);
6643 seq
= reserve_crit(size
, "xrealloc", seq
);
6644 ret
= iralloc(ptr
, size
);
6645 } while (ret
== NULL
);
6649 reserve_fail(size
, "xrealloc");
6651 ret
= imalloc(size
);
6656 seq
= reserve_crit(size
, "xrealloc", seq
);
6657 ret
= imalloc(size
);
6658 } while (ret
== NULL
);
6662 UTRACE(ptr
, size
, ret
);
6667 xmemalign(size_t alignment
, size_t size
)
6671 assert(((alignment
- 1) & alignment
) == 0 && alignment
>=
6675 reserve_fail(size
, "xmemalign");
6677 ret
= ipalloc(alignment
, size
);
6682 seq
= reserve_crit(size
, "xmemalign", seq
);
6683 ret
= ipalloc(alignment
, size
);
6684 } while (ret
== NULL
);
6687 UTRACE(0, size
, ret
);
6692 reserve_shrink(void)
6694 extent_node_t
*node
;
6696 assert(reserve_cur
> reserve_max
);
6699 extent_node_t
*node
;
6700 size_t reserve_size
;
6703 rb_foreach_begin(extent_node_t
, link_szad
, &reserve_chunks_szad
,
6705 reserve_size
+= node
->size
;
6706 } rb_foreach_end(extent_node_t
, link_szad
, &reserve_chunks_szad
,
6708 assert(reserve_size
== reserve_cur
);
6711 rb_foreach_begin(extent_node_t
, link_ad
, &reserve_chunks_ad
,
6713 reserve_size
+= node
->size
;
6714 } rb_foreach_end(extent_node_t
, link_ad
, &reserve_chunks_ad
,
6716 assert(reserve_size
== reserve_cur
);
6720 /* Discard chunks until the the reserve is below the size limit. */
6721 rb_foreach_reverse_begin(extent_node_t
, link_ad
, &reserve_chunks_ad
,
6723 #ifndef MALLOC_DECOMMIT
6724 if (node
->size
<= reserve_cur
- reserve_max
) {
6726 extent_node_t
*tnode
= extent_tree_ad_prev(
6727 &reserve_chunks_ad
, node
);
6729 #ifdef MALLOC_DECOMMIT
6730 assert(node
->size
<= reserve_cur
- reserve_max
);
6733 /* Discard the entire [multi-]chunk. */
6734 extent_tree_szad_remove(&reserve_chunks_szad
, node
);
6735 extent_tree_ad_remove(&reserve_chunks_ad
, node
);
6736 reserve_cur
-= node
->size
;
6737 pages_unmap(node
->addr
, node
->size
);
6739 stats_chunks
.curchunks
-= (node
->size
/ chunksize
);
6741 base_node_dealloc(node
);
6742 if (reserve_cur
== reserve_max
)
6745 rb_foreach_reverse_prev(extent_node_t
, link_ad
,
6746 extent_ad_comp
, &reserve_chunks_ad
, tnode
);
6747 #ifndef MALLOC_DECOMMIT
6749 /* Discard the end of the multi-chunk. */
6750 extent_tree_szad_remove(&reserve_chunks_szad
, node
);
6751 node
->size
-= reserve_cur
- reserve_max
;
6752 extent_tree_szad_insert(&reserve_chunks_szad
, node
);
6753 pages_unmap((void *)((uintptr_t)node
->addr
+
6754 node
->size
), reserve_cur
- reserve_max
);
6756 stats_chunks
.curchunks
-= ((reserve_cur
- reserve_max
) /
6759 reserve_cur
= reserve_max
;
6763 assert(reserve_cur
> reserve_max
);
6764 } rb_foreach_reverse_end(extent_node_t
, link_ad
, &reserve_chunks_ad
,
6768 /* Send a condition notification. */
6770 reserve_notify(reserve_cnd_t cnd
, size_t size
, uint64_t seq
)
6774 /* seq is used to keep track of distinct condition-causing events. */
6776 /* Allocate new sequence number. */
6782 * Advance to the next callback registration and send a notification,
6783 * unless one has already been sent for this condition-causing event.
6785 reg
= ql_first(&reserve_regs
);
6788 ql_first(&reserve_regs
) = ql_next(&reserve_regs
, reg
, link
);
6789 if (reg
->seq
== seq
)
6792 malloc_mutex_unlock(&reserve_mtx
);
6793 reg
->cb(reg
->ctx
, cnd
, size
);
6794 malloc_mutex_lock(&reserve_mtx
);
6799 /* Allocation failure due to OOM. Try to free some memory via callbacks. */
6801 reserve_crit(size_t size
, const char *fname
, uint64_t seq
)
6805 * Send one condition notification. Iteration is handled by the
6806 * caller of this function.
6808 malloc_mutex_lock(&reserve_mtx
);
6809 seq
= reserve_notify(RESERVE_CND_CRIT
, size
, seq
);
6810 malloc_mutex_unlock(&reserve_mtx
);
6812 /* If no notification could be sent, then no further recourse exists. */
6814 reserve_fail(size
, fname
);
6819 /* Permanent allocation failure due to OOM. */
6821 reserve_fail(size_t size
, const char *fname
)
6825 /* Send fail notifications. */
6826 malloc_mutex_lock(&reserve_mtx
);
6828 seq
= reserve_notify(RESERVE_CND_FAIL
, size
, seq
);
6830 malloc_mutex_unlock(&reserve_mtx
);
6832 /* Terminate the application. */
6833 _malloc_message(_getprogname(),
6834 ": (malloc) Error in ", fname
, "(): out of memory\n");
6839 reserve_cb_register(reserve_cb_t
*cb
, void *ctx
)
6841 reserve_reg_t
*reg
= base_reserve_reg_alloc();
6845 ql_elm_new(reg
, link
);
6850 malloc_mutex_lock(&reserve_mtx
);
6851 ql_head_insert(&reserve_regs
, reg
, link
);
6852 malloc_mutex_unlock(&reserve_mtx
);
6858 reserve_cb_unregister(reserve_cb_t
*cb
, void *ctx
)
6860 reserve_reg_t
*reg
= NULL
;
6862 malloc_mutex_lock(&reserve_mtx
);
6863 ql_foreach(reg
, &reserve_regs
, link
) {
6864 if (reg
->cb
== cb
&& reg
->ctx
== ctx
) {
6865 ql_remove(&reserve_regs
, reg
, link
);
6869 malloc_mutex_unlock(&reserve_mtx
);
6872 base_reserve_reg_dealloc(reg
);
6878 reserve_cur_get(void)
6882 malloc_mutex_lock(&reserve_mtx
);
6884 malloc_mutex_unlock(&reserve_mtx
);
6890 reserve_min_get(void)
6894 malloc_mutex_lock(&reserve_mtx
);
6896 malloc_mutex_unlock(&reserve_mtx
);
6902 reserve_min_set(size_t min
)
6905 min
= CHUNK_CEILING(min
);
6907 malloc_mutex_lock(&reserve_mtx
);
6908 /* Keep |reserve_max - reserve_min| the same. */
6909 if (min
< reserve_min
) {
6910 reserve_max
-= reserve_min
- min
;
6913 /* Protect against wrap-around. */
6914 if (reserve_max
+ min
- reserve_min
< reserve_max
) {
6915 reserve_min
= SIZE_T_MAX
- (reserve_max
- reserve_min
)
6917 reserve_max
= SIZE_T_MAX
- chunksize
+ 1;
6919 reserve_max
+= min
- reserve_min
;
6924 /* Resize the reserve if necessary. */
6925 if (reserve_cur
< reserve_min
) {
6926 size_t size
= reserve_min
- reserve_cur
;
6928 /* Force the reserve to grow by allocating/deallocating. */
6929 malloc_mutex_unlock(&reserve_mtx
);
6930 #ifdef MALLOC_DECOMMIT
6935 n
= size
>> opt_chunk_2pow
;
6936 chunks
= (void**)imalloc(n
* sizeof(void *));
6939 for (i
= 0; i
< n
; i
++) {
6940 chunks
[i
] = huge_malloc(chunksize
, false);
6941 if (chunks
[i
] == NULL
) {
6944 for (j
= 0; j
< i
; j
++) {
6945 huge_dalloc(chunks
[j
]);
6951 for (i
= 0; i
< n
; i
++)
6952 huge_dalloc(chunks
[i
]);
6957 void *x
= huge_malloc(size
, false);
6964 } else if (reserve_cur
> reserve_max
) {
6966 malloc_mutex_unlock(&reserve_mtx
);
6968 malloc_mutex_unlock(&reserve_mtx
);
6973 #ifdef MOZ_MEMORY_WINDOWS
6975 _recalloc(void *ptr
, size_t count
, size_t size
)
6977 size_t oldsize
= (ptr
!= NULL
) ? isalloc(ptr
) : 0;
6978 size_t newsize
= count
* size
;
6981 * In order for all trailing bytes to be zeroed, the caller needs to
6982 * use calloc(), followed by recalloc(). However, the current calloc()
6983 * implementation only zeros the bytes requested, so if recalloc() is
6984 * to work 100% correctly, calloc() will need to change to zero
6988 ptr
= realloc(ptr
, newsize
);
6989 if (ptr
!= NULL
&& oldsize
< newsize
) {
6990 memset((void *)((uintptr_t)ptr
+ oldsize
), 0, newsize
-
6998 * This impl of _expand doesn't ever actually expand or shrink blocks: it
6999 * simply replies that you may continue using a shrunk block.
7002 _expand(void *ptr
, size_t newsize
)
7004 if (isalloc(ptr
) >= newsize
)
7011 _msize(const void *ptr
)
7014 return malloc_usable_size(ptr
);
7019 * End non-standard functions.
7021 /******************************************************************************/
7023 * Begin library-private functions, used by threading libraries for protection
7024 * of malloc during fork(). These functions are only called if the program is
7025 * running in threaded mode, so there is no need to check whether the program
7030 _malloc_prefork(void)
7034 /* Acquire all mutexes in a safe order. */
7036 malloc_spin_lock(&arenas_lock
);
7037 for (i
= 0; i
< narenas
; i
++) {
7038 if (arenas
[i
] != NULL
)
7039 malloc_spin_lock(&arenas
[i
]->lock
);
7041 malloc_spin_unlock(&arenas_lock
);
7043 malloc_mutex_lock(&base_mtx
);
7045 malloc_mutex_lock(&huge_mtx
);
7049 _malloc_postfork(void)
7053 /* Release all mutexes, now that fork() has completed. */
7055 malloc_mutex_unlock(&huge_mtx
);
7057 malloc_mutex_unlock(&base_mtx
);
7059 malloc_spin_lock(&arenas_lock
);
7060 for (i
= 0; i
< narenas
; i
++) {
7061 if (arenas
[i
] != NULL
)
7062 malloc_spin_unlock(&arenas
[i
]->lock
);
7064 malloc_spin_unlock(&arenas_lock
);
7068 * End library-private functions.
7070 /******************************************************************************/
7076 #ifdef MOZ_MEMORY_DARWIN
7077 static malloc_zone_t zone
;
7078 static struct malloc_introspection_t zone_introspect
;
7081 zone_size(malloc_zone_t
*zone
, void *ptr
)
7085 * There appear to be places within Darwin (such as setenv(3)) that
7086 * cause calls to this function with pointers that *no* zone owns. If
7087 * we knew that all pointers were owned by *some* zone, we could split
7088 * our zone into two parts, and use one as the default allocator and
7089 * the other as the default deallocator/reallocator. Since that will
7090 * not work in practice, we must check all pointers to assure that they
7091 * reside within a mapped chunk before determining size.
7093 return (isalloc_validate(ptr
));
7097 zone_malloc(malloc_zone_t
*zone
, size_t size
)
7100 return (malloc(size
));
7104 zone_calloc(malloc_zone_t
*zone
, size_t num
, size_t size
)
7107 return (calloc(num
, size
));
7111 zone_valloc(malloc_zone_t
*zone
, size_t size
)
7113 void *ret
= NULL
; /* Assignment avoids useless compiler warning. */
7115 posix_memalign(&ret
, pagesize
, size
);
7121 zone_free(malloc_zone_t
*zone
, void *ptr
)
7128 zone_realloc(malloc_zone_t
*zone
, void *ptr
, size_t size
)
7131 return (realloc(ptr
, size
));
7135 zone_destroy(malloc_zone_t
*zone
)
7138 /* This function should never be called. */
7144 zone_good_size(malloc_zone_t
*zone
, size_t size
)
7150 * Actually create an object of the appropriate size, then find out
7151 * how large it could have been without moving up to the next size
7165 zone_force_lock(malloc_zone_t
*zone
)
7172 zone_force_unlock(malloc_zone_t
*zone
)
7178 static malloc_zone_t
*
7182 assert(malloc_initialized
);
7184 zone
.size
= (void *)zone_size
;
7185 zone
.malloc
= (void *)zone_malloc
;
7186 zone
.calloc
= (void *)zone_calloc
;
7187 zone
.valloc
= (void *)zone_valloc
;
7188 zone
.free
= (void *)zone_free
;
7189 zone
.realloc
= (void *)zone_realloc
;
7190 zone
.destroy
= (void *)zone_destroy
;
7191 zone
.zone_name
= "jemalloc_zone";
7192 zone
.batch_malloc
= NULL
;
7193 zone
.batch_free
= NULL
;
7194 zone
.introspect
= &zone_introspect
;
7196 zone_introspect
.enumerator
= NULL
;
7197 zone_introspect
.good_size
= (void *)zone_good_size
;
7198 zone_introspect
.check
= NULL
;
7199 zone_introspect
.print
= NULL
;
7200 zone_introspect
.log
= NULL
;
7201 zone_introspect
.force_lock
= (void *)zone_force_lock
;
7202 zone_introspect
.force_unlock
= (void *)zone_force_unlock
;
7203 zone_introspect
.statistics
= NULL
;
7208 __attribute__((constructor
))
7210 jemalloc_darwin_init(void)
7212 extern unsigned malloc_num_zones
;
7213 extern malloc_zone_t
**malloc_zones
;
7215 if (malloc_init_hard())
7219 * The following code is *not* thread-safe, so it's critical that
7220 * initialization be manually triggered.
7223 /* Register the custom zones. */
7224 malloc_zone_register(create_zone());
7225 assert(malloc_zones
[malloc_num_zones
- 1] == &zone
);
7228 * Shift malloc_zones around so that zone is first, which makes it the
7231 assert(malloc_num_zones
> 1);
7232 memmove(&malloc_zones
[1], &malloc_zones
[0],
7233 sizeof(malloc_zone_t
*) * (malloc_num_zones
- 1));
7234 malloc_zones
[0] = &zone
;
7237 #elif defined(__GLIBC__) && !defined(__UCLIBC__)
7239 * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
7240 * to inconsistently reference libc's malloc(3)-compatible functions
7243 * These definitions interpose hooks in glibc. The functions are actually
7244 * passed an extra argument for the caller return address, which will be
7247 void (*__free_hook
)(void *ptr
) = free
;
7248 void *(*__malloc_hook
)(size_t size
) = malloc
;
7249 void *(*__realloc_hook
)(void *ptr
, size_t size
) = realloc
;
7250 void *(*__memalign_hook
)(size_t alignment
, size_t size
) = memalign
;
7252 #elif defined(RTLD_DEEPBIND)
7254 * XXX On systems that support RTLD_GROUP or DF_1_GROUP, do their
7255 * implementations permit similar inconsistencies? Should STV_SINGLETON
7256 * visibility be used for interposition where available?
7258 # error "Interposing malloc is unsafe on this system without libc malloc hooks."