AIThis post was created with the assistance of artificial intelligence (AI).

TL;DR

Buying for a business?Offer from Amazon

Get business pricing on monitors, keyboards and dev gear

  • Business-only prices and quantity discounts
  • Tax-exempt purchasing
  • Multiple users, one account, clear invoices
As an affiliate, we earn on qualifying purchases.

A report by Ben M. Andrew explains how GNU libc’s malloc handles small allocations by obtaining memory in larger blocks and managing it within the process. In one test, 1,000 calls to malloc(16) required two brk system calls, while the remaining allocations used memory already obtained.

Ben M. Andrew’s report explains how GNU libc’s malloc can satisfy many small memory requests without making a kernel system call for each one. In a test program making 1,000 calls to malloc(16), a strace trace showed two brk calls at the start, followed by allocations served from memory already acquired for the process.

The test program stores the pointers returned by 1,000 calls to malloc(16). Andrew reports that the trace showed an initial brk(NULL) call to inspect the process’s program break, followed by a call that moved the break to grow the heap by 132 KiB. The other 999 requests did not produce additional brk calls in that run. The result illustrates how the allocator can request a larger region and subdivide it for individual allocations.

Andrew compares that approach with a simple bump allocator built using sbrk, a C library wrapper for moving the program break. That toy allocator asks for more memory on every request and does not reuse space after it is freed. In the report’s timing test, an empty system call averaged 575.2 nanoseconds, sbrk(16) averaged 610.1 ns, and malloc(16) averaged 26.9 ns per call. Andrew reports the malloc call as 22.7 times faster than the sbrk call in that test.

The report also describes allocation chunks: malloc may reserve more bytes than the caller requested, including space for a size header immediately before the returned pointer. In the examples, chunk sizes are rounded to multiples of 16 bytes, with a minimum of 32 bytes. When a block is freed, the allocator can track it for possible reuse; Andrew describes free lists and the ability to split larger free chunks or combine neighbouring ones.

At a glance
reportWhen: Publication date not stated in the sour…
The developmentBen M. Andrew published a technical explainer tracing how glibc malloc requests memory from the kernel and manages allocations inside a process.

Why Small Allocations Avoid Syscalls

The explanation addresses a common source of confusion in systems programming: a call to malloc is not necessarily a request to the kernel. The allocator’s internal bookkeeping lets a program make frequent small allocations while reducing the number of comparatively expensive system calls. The 1,000-allocation example makes that distinction concrete, though it reflects one program run and one allocator configuration rather than a universal call pattern.

That distinction matters when developers interpret performance measurements or inspect a program with tracing tools. A low count of memory-related system calls does not mean the program made few allocations; many allocations may have been served from a region already obtained by the process. Conversely, the timing figures in Andrew’s report are measurements from his test setup, not guarantees for every machine, operating system, allocator version or workload.

The account also clarifies why free does not necessarily return memory to the operating system immediately. The allocator may retain a freed chunk for reuse within the process. That can make later allocations cheaper, but it means the connection between a program’s calls to malloc and free and its system-level memory use is not a simple one-to-one relationship.

Breville Barista Express Espresso Machine with Built-In Grinder, Black Sesame

Breville Barista Express Espresso Machine with Built-In Grinder, Black Sesame

KitchenAid Artisan Mini Tilt-Head Stand Mixer, 3.5 Qt, Contour Silver

KitchenAid Artisan Mini Tilt-Head Stand Mixer, 3.5 Qt, Contour Silver

As an affiliate, we earn on qualifying purchases.

From Program Break to Chunk Lists

A process has a virtual address space containing regions for executable code, global data, the heap and the stack, among others. Andrew’s examples show addresses from these regions and use the program break to identify the end of the traditional heap. Moving the break can extend that heap. The report notes that large gaps between addresses in a process’s virtual address space can be unmapped, so the distance between two addresses does not by itself mean that physical RAM has been used.

The report builds its explanation in stages. A bump allocator that advances the program break is easy to describe but asks the system for memory on each allocation and cannot reuse freed blocks. A more capable allocator needs to track chunk sizes and availability. Andrew describes a size word before the pointer returned to the caller, with low bits available for flags because chunk sizes are aligned. That metadata lets the allocator determine how much space a chunk occupies when free is called without a size argument.

In the report’s model, free chunks are linked so the allocator can search for usable space, split a larger chunk when appropriate, and merge adjacent free chunks. These mechanisms are presented as an explanation of the illustrated glibc behavior; allocator internals can differ across implementations and configurations. The supplied report excerpt ends while describing the information stored in free-list chunks, so it does not provide the full subsequent treatment.

“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, report

Limits of the Demonstration

The supplied material does not state the report’s publication date, the exact machine and software configuration used for each measurement, or whether the observed syscall pattern holds across other glibc versions and workloads. The 132 KiB heap growth and timing results should therefore be read as results from Andrew’s examples, not fixed values for all systems.

The excerpt describes glibc’s chunk bookkeeping and free-list behavior but does not include the complete article. It also does not establish that every allocation is served from the traditional heap: allocator choices can depend on implementation details and allocation patterns. The exact policies and thresholds in use for a given program are not specified here.

What to Check in a Program

Readers investigating their own programs can compare allocation calls with system-call traces, while keeping the distinction between an allocator’s internal work and kernel requests in mind. Andrew’s example uses strace to follow brk, mmap and related calls, and a separate timing program to compare selected operations. Such results need to be interpreted in light of the local operating system, allocator and test conditions.

The next step for readers seeking the full implementation account is the remainder of Andrew’s report, which the supplied excerpt does not include. No follow-up measurement or additional development is identified in the source material.

Key Questions

Does every malloc call ask the kernel for memory?

No. In Andrew’s glibc example, 1,000 calls to malloc(16) produced two brk calls, with the later allocations served from memory already obtained. Other programs and allocator conditions may behave differently.

What is the program break?

It marks the end of the process’s traditional heap. The brk system call can move it, while sbrk is a C library wrapper that requests a change by a specified amount.

Why can malloc be faster than sbrk in the report’s test?

Andrew’s measured malloc(16) call used allocator-managed memory and averaged 26.9 ns, while sbrk(16) averaged 610.1 ns. Those are results from the report’s test setup, not universal performance guarantees.

Does free immediately give memory back to the operating system?

Not necessarily. The report describes freed chunks being tracked so malloc can reuse them. It does not say that each call to free immediately returns its block to the kernel.

Why does malloc allocate more than the requested size?

In Andrew’s explanation, each chunk includes a size header and is rounded to meet alignment requirements, with a minimum chunk size. The metadata helps the allocator manage blocks and lets free operate without the caller supplying the allocation’s size.

Source: benmandrew.com

You May Also Like

Histograms and Bar Charts: Representing Data Distributions

An overview of histograms and bar charts reveals how they visualize data distributions and categories, but understanding their differences can transform your analysis skills.

Why the Central Limit Theorem Shows Up Everywhere

AIThis post was created with the assistance of artificial intelligence (AI).The Central…

Margin of Error Explained Without the Formula Panic

A clear, formula-free explanation of margin of error reveals how survey results stay reliable, encouraging you to explore the full story behind sampling variability.

What Counts as a Variable in Statistics?

I want to show you how to identify different types of variables in statistics and why it matters for your analysis.