Why malloc Pre‑allocates Memory: Inside Linux’s brk and mmap Allocation Strategies
This article explains Linux's virtual address space layout, the six user‑space memory segments, how malloc decides between brk and mmap based on allocation size, the behavior of free, and why both allocation methods are needed for performance and memory management.
Linux Virtual Address Space Overview
In Linux, the virtual address space is divided into kernel space and user space. On 32‑bit systems the kernel occupies the top 1 GB and the remaining 3 GB is user space; on 64‑bit systems both kernel and user spaces each span 128 TB, leaving an undefined middle region.
User‑Space Memory Segments
The user‑space memory is organized from low to high addresses into six segments:
Program (text) segment – executable code.
Initialized data segment – static constants.
Uninitialized data (BSS) segment – static variables without explicit initialization.
Heap – dynamically allocated memory that grows upward.
Memory‑mapped region – includes shared libraries and anonymous mappings, also growing upward.
Stack – local variables and call context, typically a fixed 8 MB size.
Both the heap and the memory‑mapped region are used by malloc() for dynamic allocation.
How malloc() Allocates Memory
malloc()is a C library function, not a system call. It chooses between two kernel mechanisms:
For requests smaller than 128 KB (default threshold in glibc), it uses the brk() system call to extend the heap.
For requests larger than 128 KB, it uses mmap() with a private anonymous mapping.
Example code allocating 1 byte demonstrates the brk() path; the /proc/<pid>/maps file shows a [heap] region of about 132 KB, confirming that malloc(1) pre‑allocates a larger chunk.
#include <stdio.h>
#include <malloc.h>
int main() {
printf("Using cat /proc/%d/maps to view memory
", getpid());
void *addr = malloc(1);
printf("1‑byte allocation address: %p
", addr);
getchar(); // pause
free(addr);
printf("Freed 1‑byte allocation; heap remains.
");
getchar();
return 0;
}Allocating 128 KB triggers the mmap() path; the resulting memory region lacks the [heap] label, indicating an anonymous mapping. After freeing, the mapping disappears, showing that the memory is returned to the kernel.
#include <stdio.h>
#include <malloc.h>
int main() {
void *addr = malloc(128*1024);
printf("128KB allocation address: %p
", addr);
getchar(); // pause
free(addr);
printf("Freed 128KB; mapping removed.
");
getchar();
return 0;
}Why Not Use Only mmap() ?
Every mmap() allocation requires a system call, causing a user‑kernel mode switch. Frequent switches increase CPU overhead. Moreover, each newly mapped page starts in a “not‑present” state, so the first access triggers a page‑fault interrupt, adding further latency.
Why Not Use Only brk() ?
Heap allocations via brk() are contiguous, so freeing memory does not return it to the kernel; instead the freed block stays in the allocator’s internal pool. Over time, repeated small allocations and frees can fragment the heap, leading to internal “leaks” that tools like valgrind cannot detect.
How free() Knows the Block Size
The pointer returned by malloc() is offset by 16 bytes from the actual start of the allocated chunk. Those 16 bytes store metadata, including the block’s size. When free() is called, it subtracts 16 bytes, reads the size, and knows exactly how much memory to release.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
