C Mastery / Allocation Failure, Fragmentation, and Alignment
Part 4 — Memory Management

Allocation Failure, Fragmentation, and Alignment

This chapter covers three practical realities of dynamic allocation: failure handling, fragmentation, and alignment.

Why This Matters

Allocation can fail, and failing to handle it is a security and robustness bug. Fragmentation degrades long-running programs. Alignment requirements can make a seemingly valid pointer undefined behavior. These are not edge cases; they are everyday systems concerns.

Prerequisites

Core Concept

Allocation failure

malloc/calloc/realloc return NULL when they cannot satisfy a request. You must check every result. Failure may be recoverable (small request) or fatal (out of memory). Robust code always checks and propagates the error.

Fragmentation

The heap is a finite region. Over time, allocation and deallocation of varying sizes can leave the free space split into many small holes — fragmentation. The total free memory may be large, but no single hole is big enough for a request. This is a property of the allocation pattern, not a leak.

Alignment

The allocator returns memory aligned for any standard type. But:

posix_memalign (platform-specific).

Examples

Handling failure

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    int *p = malloc(sizeof *p);
    if (p == NULL) {
        fputs("out of memory\n", stderr);
        return 1;
    }
    *p = 5;
    free(p);
    return 0;
}

Over-aligned allocation (C11)

#include <stdlib.h>
#include <stdalign.h>

int main(void)
{
    /* aligned_alloc: size must be a multiple of alignment */
    float *buf = aligned_alloc(32, 32 * sizeof *buf);
    if (buf == NULL) return 1;
    /* buf is 32-byte aligned */
    free(buf);
    return 0;
}

aligned_alloc is C11. On POSIX, posix_memalign is an alternative.

How It Works

The allocator tracks free blocks. A request of size N finds a free block >= N; the block may be split, leaving a smaller free block. Repeated splits and coalescing failures cause fragmentation. Alignment is guaranteed by the allocator's internal padding, but only up to the standard type alignment.

Variations

Fragmentation-resistant strategies

Pools, arenas, and slab allocators (c.memory.5) reduce fragmentation by allocating fixed sizes or freeing in bulk.

alignment check idiom

You can verify a pointer is aligned with:

#include <stdint.h>
_Bool is_aligned(void *p, size_t a) {
    return ((uintptr_t)p % a) == 0;
}

This is well-defined for the purposes of *checking* (the integer conversion is implementation-defined but yields the address value).

Common Mistakes

Undefined Behavior

miscalculating alignment/size.

Portability

MSVC. They differ in argument order and failure behavior.

Under the Hood

The allocator rounds sizes up to an alignment boundary (often 8 or 16 bytes) and stores metadata in a header. Fragmentation is visible in allocator statistics (e.g., mallinfo on glibc).

Practical Usage

short-lived groups, pools for fixed-size objects).

Exercises

1. Write a program that deliberately requests a huge allocation and handles the NULL return. 2. Demonstrate a fragmentation scenario by allocating/freeing varying sizes and observing that a large request fails even though total free memory seems sufficient (this is hard to force portably; describe the reasoning). 3. Use aligned_alloc and verify the returned pointer is aligned.

Deep Challenge

Implement a fixed-size pool allocator that is immune to fragmentation for a single object size, and explain how it differs from a general-purpose allocator. Include alignment handling and failure behavior.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.mem.failure06
c.mem.fragmentation06
c.mem.alignment06