0
0
Embedded Cprogramming~10 mins

Memory pool (fixed-size block allocator) in Embedded C

Choose your learning style9 modes available
Introduction

A memory pool helps manage memory efficiently by dividing a big chunk into small fixed-size blocks. It makes allocating and freeing memory faster and predictable.

When you need to allocate many small objects of the same size repeatedly.
In embedded systems where memory is limited and fragmentation must be avoided.
When you want fast and simple memory allocation without using the general heap.
For real-time systems where predictable allocation time is important.
Syntax
Embedded C
typedef struct MemoryPool {
    void *pool_start;
    size_t block_size;
    size_t total_blocks;
    void *free_list;
} MemoryPool;

void MemoryPool_init(MemoryPool *mp, void *buffer, size_t block_size, size_t total_blocks);
void *MemoryPool_alloc(MemoryPool *mp);
void MemoryPool_free(MemoryPool *mp, void *block);

The pool is created from a buffer you provide.

Blocks are all the same size for simplicity and speed.

Examples
Initialize a memory pool with 32 blocks of 32 bytes each inside a 1024-byte buffer.
Embedded C
MemoryPool mp;
char buffer[1024];
MemoryPool_init(&mp, buffer, 32, 32);
Allocate one block from the pool. Check if allocation succeeded.
Embedded C
void *block = MemoryPool_alloc(&mp);
if (block != NULL) {
    // use the block
}
Return the block back to the pool when done.
Embedded C
MemoryPool_free(&mp, block);
Sample Program

This program creates a memory pool with 8 blocks of 16 bytes each. It allocates all blocks, tries to allocate one more (which fails), frees one block, and then allocates again successfully.

Embedded C
#include <stdio.h>
#include <stddef.h>

typedef struct MemoryPool {
    void *pool_start;
    size_t block_size;
    size_t total_blocks;
    void *free_list;
} MemoryPool;

void MemoryPool_init(MemoryPool *mp, void *buffer, size_t block_size, size_t total_blocks) {
    mp->pool_start = buffer;
    mp->block_size = block_size;
    mp->total_blocks = total_blocks;
    mp->free_list = buffer;

    // Link all blocks in the free list
    char *p = (char *)buffer;
    for (size_t i = 0; i < total_blocks - 1; i++) {
        *(void **)p = p + block_size; // next pointer
        p += block_size;
    }
    *(void **)p = NULL; // last block points to NULL
}

void *MemoryPool_alloc(MemoryPool *mp) {
    if (mp->free_list == NULL) {
        return NULL; // no free blocks
    }
    void *block = mp->free_list;
    mp->free_list = *(void **)block; // move free_list to next
    return block;
}

void MemoryPool_free(MemoryPool *mp, void *block) {
    *(void **)block = mp->free_list;
    mp->free_list = block;
}

int main() {
    char buffer[128];
    MemoryPool mp;
    MemoryPool_init(&mp, buffer, 16, 8); // 8 blocks of 16 bytes

    void *blocks[8];

    // Allocate all blocks
    for (int i = 0; i < 8; i++) {
        blocks[i] = MemoryPool_alloc(&mp);
        if (blocks[i] != NULL) {
            printf("Allocated block %d at %p\n", i, blocks[i]);
        } else {
            printf("Failed to allocate block %d\n", i);
        }
    }

    // Try to allocate one more block (should fail)
    void *extra = MemoryPool_alloc(&mp);
    if (extra == NULL) {
        printf("No more blocks available\n");
    }

    // Free one block
    MemoryPool_free(&mp, blocks[3]);
    printf("Freed block 3\n");

    // Allocate again (should succeed)
    void *new_block = MemoryPool_alloc(&mp);
    if (new_block != NULL) {
        printf("Allocated new block at %p\n", new_block);
    }

    return 0;
}
OutputSuccess
Important Notes

Memory pools avoid fragmentation by using fixed-size blocks.

Always free blocks back to the pool to reuse memory.

Do not free blocks not allocated from the pool or double free.

Summary

A memory pool divides memory into fixed-size blocks for fast allocation.

It is useful in embedded and real-time systems to manage memory predictably.

Initialize the pool, allocate blocks, and free them when done.