mallopt(3)
๐ mallopt(3) ยท from the Library Functions Manual ยท bestie edition ๐
โจ NAME โจ
mallopt โ set memory allocation parameters ๐ซถ
๐ LIBRARY ๐
Standard C library (libc, -lc) โ she's built in, no extra downloads, we love a low-effort queen โจ
๐ฆ SYNOPSIS ๐ฆ
#include <malloc.h>
int mallopt(int param, int value);
๐ DESCRIPTION ๐
okay so bestie, listen up, because this one is lowkey the CEO of "why is my memory doing that" ๐ญ
mallopt() is the function you hit up when you want to adjust the parameters that control how the memory-allocation girlies behave (that's malloc(3) and her whole entourage). The param argument says which parameter you're modifying, and value says what you're setting it to. That's it, that's the whole vibe check.
These are the values you can slide into param ๐
๐๏ธ M_ARENA_MAX
If this parameter has a nonzero value, it becomes a hard limit on the max number of arenas that can be created. And queen, if you're wondering what an arena even is: it's a pool of memory that malloc(3) (and similar) calls can use to service allocation requests. Arenas are thread safe, so they can totally have multiple concurrent memory requests going at once. ๐
Here's the trade-off, and it's giving math: it's a balance between the number of threads and the number of arenas. The more arenas you have, the lower the per-thread contention โ but the higher the memory usage. Choose your fighter.
The default value of this parameter is 0, which means the limit on the number of arenas gets determined according to the setting of M_ARENA_TEST instead.
This parameter has been available since glibc 2.10 via --enable-experimental-malloc, and since glibc 2.15 by default. (In some versions of the allocator there was no limit at all on the number of created arenas โ e.g., CentOS 5, RHEL 5. wild.)
When you're running newer glibc versions, applications may in some cases exhibit high contention when accessing arenas. When that happens, it may be beneficial to increase M_ARENA_MAX to match the number of threads. That's similar in behavior to strategies taken by tcmalloc and jemalloc (e.g., per-thread allocation pools). iykyk ๐
๐งช M_ARENA_TEST
This parameter specifies a value, in number of arenas created, at which point the system configuration gets examined to determine a hard limit on the number of created arenas. (Scoot over to M_ARENA_MAX for the definition of an arena, bestie, we covered that.)
The computation of the arena hard limit is implementation-defined, and it's usually calculated as a multiple of the number of available CPUs. Once that hard limit is computed, the result is final โ it constrains the total number of arenas, periodt.
The default value for the M_ARENA_TEST parameter is 2 on systems where sizeof(long) is 4; otherwise the default value is 8.
This parameter has been available since glibc 2.10 via --enable-experimental-malloc, and since glibc 2.15 by default. โจ
๐จ note: the value ofM_ARENA_TESTis not used whenM_ARENA_MAXhas a nonzero value. she said no overlap ๐
๐ต๏ธ M_CHECK_ACTION
Setting this parameter controls how glibc responds when various kinds of programming errors are detected (e.g., freeing the same pointer twice โ embarrassing, we've all been there ๐ซฃ). The 3 least significant bits (2, 1, and 0) of the value assigned to this parameter determine the glibc behavior, like this:
- Bit 0 โ If this bit is set, then print a one-line message on
stderrthat provides details about the error. The message starts with the string"*** glibc detected ***", followed by the program name, the name of the memory-allocation function in which the error was detected, a brief description of the error, and the memory address where the error was detected. - Bit 1 โ If this bit is set, then, after printing any error message specified by bit 0, the program is terminated by calling
abort(3). Since glibc 2.4, if bit 0 is also set, then, between printing the error message and aborting, the program also prints a stack trace in the manner ofbacktrace(3), and prints the process's memory mapping in the style of/proc/pid/maps(seeproc(5)). ๐ - Bit 2 (since glibc 2.4) โ This bit has an effect only if bit 0 is also set. If this bit is set, then the one-line message describing the error is simplified to contain just the name of the function where the error was detected and the brief description of the error. short & sweet, we love her.
The remaining bits in value are ignored. ๐
Putting all of that together, these numeric values are the meaningful ones for M_CHECK_ACTION:
0โ Ignore error conditions; continue execution (with undefined results). live dangerously ig1โ Print a detailed error message and continue execution.2โ Abort the program.3โ Print detailed error message, stack trace, and memory mappings, and abort the program.5โ Print a simple error message and continue execution.7โ Print simple error message, stack trace, and memory mappings, and abort the program.
Since glibc 2.3.4, the default value for the M_CHECK_ACTION parameter is 3. In glibc 2.3.3 and earlier, the default value is 1. โญ
๐ก Using a nonzero M_CHECK_ACTION value can be useful, because otherwise a crash may happen much later, and the true cause of the problem is then very hard to track down. trust me bestie, you want the receipts.
๐บ๏ธ M_MMAP_MAX
This parameter specifies the maximum number of allocation requests that may be simultaneously serviced using mmap(2). She exists because some systems have a limited number of internal tables for use by mmap(2), and using more than a few of them may degrade performance. ๐ญ
The default value is 65,536 โ a value which has no special significance and which serves only as a safeguard. Setting this parameter to 0 disables the use of mmap(2) for servicing large allocation requests.
๐ M_MMAP_THRESHOLD
For allocations greater than or equal to the limit specified (in bytes) by M_MMAP_THRESHOLD that can't be satisfied from the free list, the memory-allocation functions employ mmap(2) instead of increasing the program break using sbrk(2). โจ
Allocating memory using mmap(2) has the significant advantage that the allocated memory blocks can always be independently released back to the system. (By contrast, the heap can be trimmed only if memory is freed at the top end. mid tbh.) On the other hand, there are some disadvantages to the use of mmap(2):
- deallocated space is not placed on the free list for reuse by later allocations
- memory may be wasted because
mmap(2)allocations must be page-aligned - the kernel must perform the expensive task of zeroing out memory allocated via
mmap(2)๐ฎโ๐จ
Balancing all these factors leads to a default setting of 128*1024 for the M_MMAP_THRESHOLD parameter.
The lower limit for this parameter is 0. The upper limit is DEFAULT_MMAP_THRESHOLD_MAX: 512*1024 on 32-bit systems or 4*1024*1024*sizeof(long) on 64-bit systems.
๐ข Note: Nowadays, glibc uses a dynamic mmap threshold by default. The initial value of the threshold is128*1024, but when blocks larger than the current threshold and less than or equal toDEFAULT_MMAP_THRESHOLD_MAXare freed, the threshold is adjusted upward to the size of the freed block. When dynamic mmap thresholding is in effect, the threshold for trimming the heap is also dynamically adjusted to be twice the dynamic mmap threshold. Dynamic adjustment of the mmap threshold is disabled if any of theM_TRIM_THRESHOLD,M_TOP_PAD,M_MMAP_THRESHOLD, orM_MMAP_MAXparameters is set. ๐ซถ
โก M_MXFAST (since glibc 2.3)
Set the upper limit for memory allocation requests that are satisfied using "fastbins". (The measurement unit for this parameter is bytes, bestie.) Fastbins are storage areas that hold deallocated blocks of memory of the same size without merging adjacent free blocks. Subsequent reallocation of blocks of the same size can then be handled very quickly by allocating from the fastbin โ although memory fragmentation and the overall memory footprint of the program can increase. speed vs. chaos, the eternal struggle ๐
The default value for this parameter is 64*sizeof(size_t)/4 (i.e., 64 on 32-bit architectures). The range for this parameter is 0 to 80*sizeof(size_t)/4. Setting M_MXFAST to 0 disables the use of fastbins.
๐ซ๏ธ M_PERTURB (since glibc 2.4)
If this parameter is set to a nonzero value, then bytes of allocated memory (other than allocations via calloc(3)) are initialized to the complement of the value in the least significant byte of value, and when allocated memory is released using free(3), the freed bytes are set to the least significant byte of value. ๐
This can be useful for detecting errors where programs incorrectly rely on allocated memory being initialized to zero, or reuse values in memory that has already been freed. detective mode, activated ๐
The default value for this parameter is 0.
๐งธ M_TOP_PAD
This parameter defines the amount of padding to employ when calling sbrk(2) to modify the program break. (The measurement unit for this parameter is bytes.) This parameter has an effect in the following circumstances:
- When the program break is increased, then
M_TOP_PADbytes are added to thesbrk(2)request. - When the heap is trimmed as a consequence of calling
free(3)(see the discussion ofM_TRIM_THRESHOLD), this much free space is preserved at the top of the heap.
In either case, the amount of padding is always rounded to a system page boundary. ๐ธ
Modifying M_TOP_PAD is a trade-off between increasing the number of system calls (when the parameter is set low) and wasting unused memory at the top of the heap (when the parameter is set high). pick your struggle fr fr
The default value for this parameter is 128*1024.
โ๏ธ M_TRIM_THRESHOLD
When the amount of contiguous free memory at the top of the heap grows sufficiently large, free(3) employs sbrk(2) to release this memory back to the system. (This can be useful in programs that continue to execute for a long period after freeing a significant amount of memory.) The M_TRIM_THRESHOLD parameter specifies the minimum size (in bytes) that this block of memory must reach before sbrk(2) is used to trim the heap. ๐
The default for this one is 128*1024. And if you go and set M_TRIM_THRESHOLD to -1, trimming gets disabled completely โ like, gone gone.
Tweaking M_TRIM_THRESHOLD is genuinely a trade-off, bestie: crank it low and you're making way more system calls; crank it high and you're wasting unused memory at the top of the heap. There's no free lunch, only different flavors of struggle. ๐
๐ฟ Environment variables ๐ฟ
Okay so plot twist: you can define a whole bunch of environment variables to mess with some of the exact same parameters that mallopt() controls. The slay part? You don't have to change a single line of the program's source code.
But to actually do anything, these variables must be defined before the first call to a memory-allocation function. Also โ if the same parameter is adjusted via mallopt() as well, then the mallopt() settings take precedence. Periodt. And for security reasons, these variables are ignored in set-user-ID and set-group-ID programs. Sorry bestie, that's just how it is. ๐
Here's the whole roster (and yes, note the trailing underscore on the end of some of these names โ that's not a typo, that's the vibe):
MALLOC_ARENA_MAXโ controls the same parameter asmallopt()M_ARENA_MAX.MALLOC_ARENA_TESTโ controls the same parameter asmallopt()M_ARENA_TEST.MALLOC_CHECK_โ controls the same parameter asmallopt()M_CHECK_ACTION. If this variable is set to a nonzero value, then a special implementation of the memory-allocation functions gets used instead. (This is accomplished using themalloc_hook(3)feature.) That implementation does additional error checking, but ngl it's slower than the standard set of memory-allocation functions. And heads up: this implementation does not detect all possible errors โ memory leaks can still occur. ๐
The value you assign to this environment variable should be a single digit, whose meaning is as described for M_CHECK_ACTION. Any characters beyond that initial digit are just ignored.
For security reasons, the effect of MALLOC_CHECK_ is disabled by default for set-user-ID and set-group-ID programs. However โ if the file /etc/suid-debug exists (the content of the file is irrelevant, literally whatever), then MALLOC_CHECK_ also has an effect for set-user-ID and set-group-ID programs. โจ
MALLOC_MMAP_MAX_โ controls the same parameter asmallopt()M_MMAP_MAX.MALLOC_MMAP_THRESHOLD_โ controls the same parameter asmallopt()M_MMAP_THRESHOLD.MALLOC_PERTURB_โ controls the same parameter asmallopt()M_PERTURB.MALLOC_TRIM_THRESHOLD_โ controls the same parameter asmallopt()M_TRIM_THRESHOLD.MALLOC_TOP_PAD_โ controls the same parameter asmallopt()M_TOP_PAD.
โจ RETURN VALUE โจ
Win: mallopt() returns 1. L: it returns 0.
๐ญ ERRORS ๐ญ
On error, errno is not set. So don't go looking for it, it's not there.
๐ฆ VERSIONS ๐ฆ
A similar function exists on many System V derivatives, but the range of values for param varies across systems. The SVID defined the options M_MXFAST, M_NLBLKS, M_GRAIN, and M_KEEP, but out of that entire little list, only the first one โ M_MXFAST โ is actually implemented in glibc.
๐ STANDARDS ๐
None. Nada. Zero. Not a single standard claims this one.
๐ HISTORY ๐
glibc 2.0. OG status.
๐ BUGS ๐
Specifying an invalid value for param does not generate an error. Yep. It just... sits there. Vibes only.
A calculation error within the glibc implementation means that a call of the form:
mallopt(M_MXFAST, n)
does not result in fastbins being employed for all allocations of size up to n. To ensure the results you actually want, n should be rounded up to the next multiple greater than or equal to (2k+1)*sizeof(size_t), where k is an integer.
If mallopt() is used to set M_PERTURB, then, as expected, the bytes of allocated memory are initialized to the complement of the byte in value, and when that memory is freed, the bytes of the region are initialized to the byte specified in value. However โ there is an off-by-sizeof(size_t) error in the implementation: instead of initializing precisely the block of memory being freed by the call free(p), the block starting at p+sizeof(size_t) is initialized. ๐ Iconic behavior, honestly.
๐ EXAMPLES ๐
The program below demonstrates the use of M_CHECK_ACTION. If the program is supplied with an (integer) command-line argument, then that argument is used to set the M_CHECK_ACTION parameter. The program then allocates a block of memory, and frees it twice โ which, yeah, is an error. ๐ญ
The following shell session shows what happens when we run this program under glibc, with the default value for M_CHECK_ACTION:
$ ./a.out;
main(): returned from first free() call
*** glibc detected *** ./a.out: double free or corruption (top): 0x09d30008 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0x523501]
/lib/libc.so.6(+0x6dd70)[0x524d70]
/lib/libc.so.6(cfree+0x6d)[0x527e5d]
./a.out[0x80485db]
/lib/libc.so.6(__libc_start_main+0xe7)[0x4cdce7]
./a.out[0x8048471]
======= Memory map: ========
001e4000-001fe000 r-xp 00000000 08:06 1083555 /lib/libgcc_s.so.1
001fe000-001ff000 r--p 00019000 08:06 1083555 /lib/libgcc_s.so.1
[some lines omitted]
b7814000-b7817000 rw-p 00000000 00:00 0
bff53000-bff74000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
The following runs show the results when employing other values for M_CHECK_ACTION:
$ ./a.out 1; # Diagnose error and continue
main(): returned from first free() call
*** glibc detected *** ./a.out: double free or corruption (top): 0x09cbe008 ***
main(): returned from second free() call
$ ./a.out 2; # Abort without error message
main(): returned from first free() call
Aborted (core dumped)
$ ./a.out 0; # Ignore error and continue
main(): returned from first free() call
main(): returned from second free() call
The next run shows how to set the same parameter using the MALLOC_CHECK_ environment variable:
$ MALLOC_CHECK_=1 ./a.out;
main(): returned from first free() call
*** glibc detected *** ./a.out: free(): invalid pointer: 0x092c2008 ***
main(): returned from second free() call
๐ธ Program source ๐ธ
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
char *p;
if (argc > 1) {
if (mallopt(M_CHECK_ACTION, atoi(argv[1])) != 1) {
fprintf(stderr, "mallopt() failed");
exit(EXIT_FAILURE);
}
}
p = malloc(1000);
if (p == NULL) {
fprintf(stderr, "malloc() failed");
exit(EXIT_FAILURE);
}
free(p);
printf("%s(): returned from first free() call\n", __func__);
free(p);
printf("%s(): returned from second free() call\n", __func__);
exit(EXIT_SUCCESS);
}
๐ซถ SEE ALSO ๐ซถ
Your reading list, bestie:
mmap(2)sbrk(2)mallinfo(3)malloc(3)malloc_hook(3)malloc_info(3)malloc_stats(3)malloc_trim(3)mcheck(3)mtrace(3)posix_memalign(3)
And that's a wrap on mallopt(3)! ๐ This whole thing came from Linux man-pages 6.20, dated 2026-02-08 โ go drink some water, go read malloc(3), and go forth and not double-free anything. Slay. โจ๐๐ฆ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 2012, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms