TL;DR
Get business pricing on monitors, keyboards and dev gear
- Business-only prices and quantity discounts
- Tax-exempt purchasing
- Multiple users, one account, clear invoices
A report by Ben M. Andrew explains how GNU libc’s malloc handles small memory requests without asking the kernel for memory each time. In the author’s test, 1,000 allocations of 16 bytes required only two brk calls; allocator bookkeeping lets later requests use memory already obtained from the operating system.
A technical report by Ben M. Andrew explains how GNU libc’s malloc can satisfy many small memory requests with only a small number of calls to the kernel. In a test program that requests 16 bytes 1,000 times, tracing showed two brk system calls, both during the first allocation; the remaining requests used memory the allocator had already obtained.
The result illustrates why malloc is not simply a direct request to the operating system for every block. In Andrew’s test, glibc first queried the process’s program break—the boundary of the traditional heap—and then moved it to obtain more address space. The allocator handled the other 999 requests from that larger pool. The report’s trace shows the calls as brk(NULL) and brk(...); it does not show a separate kernel request for each 16-byte allocation.
Andrew compares this approach with a basic “bump allocator” built around sbrk, a C library wrapper that adjusts the program break by a requested amount. Such an allocator can return the next available address, but making a system call for each request adds overhead. In the report’s timing test, an empty system call averaged 575.2 nanoseconds, sbrk(16) averaged 610.1 nanoseconds, and malloc(16) averaged 26.9 nanoseconds. Those are measurements from the author’s test environment, not universal timings for all systems.
The report then describes the bookkeeping behind allocations. A glibc chunk includes metadata before the pointer returned to the program, allowing free to identify the chunk without the caller supplying its size. Andrew’s examples show chunk sizes rounded to multiples of 16 bytes, with a minimum of 32 bytes in the illustrated setup. Freed chunks can be kept for reuse; by contrast, the toy bump allocator in the report cannot reclaim a freed block for a later request.
Why Small Allocations Stay Fast
The practical point is that malloc manages memory in user space as well as obtaining it from the operating system. By requesting a larger amount and dividing it into chunks, an allocator can avoid the cost of making a system call for every small object. This helps explain why a program can make frequent allocations without an equally frequent stream of kernel memory requests.
It also clarifies why a pointer returned by malloc does not mean the program has caused an equal-sized, immediate increase in physical memory use. Andrew’s address-space example shows a large virtual gap between the heap and other regions; most of that range is unmapped in the example. Virtual addresses describe a process’s address space, while physical memory use depends on which pages are actually mapped and used. The reported 23.4 TiB separation is specific to that run and should not be read as memory consumed by the process.
For programmers, the distinction matters when interpreting performance traces and memory usage. A small number of system calls does not mean malloc is doing no work: it is tracking chunk sizes and availability, and reusing memory where possible. The report’s examples make that hidden work visible without implying that every allocator or system follows precisely the same internal design.
Popular right now

Hisense E6SR Series 55-Inch 4K UHD Hi-QLED Roku Smart TV

Vitamix VX1 Professional-Grade Blender, 64 oz, Black

Apple AirPods Pro (1st Generation) with MagSafe Charging Case
As an affiliate, we earn on qualifying purchases.
From Program Break to Chunks
A process has a virtual address space containing regions such as executable code, initialized global data, uninitialized global data, heap space and stack space. Shared libraries also occupy address ranges. The exact layout and addresses vary between runs and systems; Andrew’s printed addresses are an illustration, not a fixed map. The program break marks the current end of the traditional heap, and changing it is one way a process can obtain more address space.
The article distinguishes brk, the system call that sets the break to a specified address, from sbrk, a library interface that adjusts it by a delta. Andrew’s simple allocator calls sbrk for each allocation and does not reuse freed memory. That design makes its limitations clear: repeated kernel interactions cost time, and a freed block can be left unused even when a later allocation could fit there.
The glibc explanation adds metadata and reuse. In the report’s examples, requested sizes are rounded to meet alignment requirements, and a chunk carries flags in low bits of its size field. When freed, chunks can be tracked for later use; the article describes free-list reuse and merging neighbouring free chunks. These details are presented as an account of the allocator examined in the report, not a promise that all C libraries use identical internals.
““malloc has a very nice and simple interface: you ask for a certain amount of memory, and you’re given a void pointer to your block of contiguous bytes.””
— Ben M. Andrew, in the report
Limits of the Demonstration
The supplied report excerpt does not state its publication date, the full machine configuration, or the compiler and runtime settings behind every measurement. The nanosecond timings should therefore be treated as results from the author’s test, not benchmark guarantees. Allocation behavior and costs can vary with the operating system, libc version, workload, architecture and process state.
The trace establishes what happened in the illustrated program, but it does not establish that glibc will always use exactly two brk calls for 1,000 small allocations. The excerpt also introduces chunk metadata, free lists and coalescing, but ends partway through its explanation of free-list bookkeeping. It does not provide a complete account of every allocation path or allocator policy. In particular, the examples should not be generalized to other allocators or all large allocations.
What the Walkthrough Explains Next
Andrew’s report continues from the chunk header into how a freed chunk is represented and reused. The described process is that malloc searches available free chunks, can split a larger chunk to serve a smaller request, and can merge adjacent free chunks. That sequence explains how an allocator can reuse memory rather than continually extending the heap, though the supplied material does not include the full subsequent implementation or its performance results.
Readers seeking to reproduce the examples would need to run them in a comparable environment and inspect the active C library and system-call trace. The report’s central finding remains bounded to its demonstrated test: 1,000 calls to malloc(16) resulted in two brk calls in that run, with later requests served from previously acquired memory.
Key Questions
Does malloc ask the kernel for memory every time?
No, not in the test described. Andrew’s glibc program made 1,000 requests for 16 bytes and the trace showed two brk calls, both during the first allocation. The allocator served the remaining requests from memory it had already obtained.
What is the difference between brk and sbrk?
In Andrew’s explanation, brk is the system call that sets the program break to a specified address. sbrk is a C library interface that adjusts the break by a requested amount.
Why is a malloc chunk larger than the requested size?
The report says glibc stores metadata before the returned pointer and rounds chunk sizes for alignment. In the illustrated examples, chunks are multiples of 16 bytes and have a minimum size of 32 bytes; these figures describe the report’s setup.
Does free immediately return memory to the operating system?
Not necessarily. The report describes freed chunks being placed in a free list for reuse, with neighbouring free chunks potentially merged. The supplied excerpt does not establish when memory is returned to the operating system.
Source: benmandrew.com
