Last active
September 25, 2021 16:03
-
-
Save sneppy/184714f0d16d17c3e6a9865185454f60 to your computer and use it in GitHub Desktop.
Example of a memory pool implementation in C with same size blocks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int main() | |
{ | |
memory_pool_create_info_t info = { | |
.block_size = 1024, | |
.block_alignment = 32, | |
.num_blocks = 128 | |
}; | |
memory_pool_t* pool = memory_pool_create(&info); | |
void* blocks[128] = {}; | |
for (int i = 0; i < 128; ++i) | |
{ | |
blocks[i] = memory_pool_malloc(pool); | |
} | |
for (int i = 0; i < 128; ++i) | |
{ | |
memory_pool_free(pool, blocks[i]); | |
} | |
memory_pool_destroy(pool); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> // posix_memalign & free | |
#include <string.h> // memcpy | |
#define BLOCK_NEXT(block, block_size) (*(void**)((char*)block + block_size)) | |
size_t align2up(size_t n, size_t m) | |
{ | |
size_t p = m - 1; | |
return (n + p) & ~p; | |
} | |
memory_pool_t* memory_pool_create(memory_pool_create_info_t const* info) | |
{ | |
size_t block_actual_size = align2up(info->block_size + sizeof(void*), info->block_alignment); | |
size_t data_size = block_actual_size * info->num_blocks; | |
void* buffer = NULL; | |
// Use malloc if you don't care about alignment or not POSIX system | |
if (posix_memalign(&buffer, info->block_alignment, data_size + sizeof(memory_pool_t)) != 0) | |
{ | |
return NULL; | |
} | |
memory_pool_t* pool = (memory_pool_t*)((char*)buffer + data_size); // Pool struct after data | |
pool->buffer = buffer; | |
pool->head = buffer; | |
memcpy(&pool->info, info, sizeof(pool->info)); | |
// Init memory blocks | |
void* tail = pool->head; | |
for (int idx = 0; idx < pool->info.num_blocks - 1; ++idx) | |
{ | |
tail = BLOCK_NEXT(tail, pool->info.block_size) = tail + block_actual_size; | |
} | |
BLOCK_NEXT(tail, pool->info.block_size) = NULL; | |
return pool; | |
} | |
void memory_pool_destroy(memory_pool_t* pool) | |
{ | |
// Maybe check all pools are returned with a loop | |
free(pool->buffer); | |
} | |
void* memory_pool_malloc(memory_pool_t* pool) | |
{ | |
if (!pool->head) | |
{ | |
// Pool exhausted | |
return NULL; | |
} | |
void* block = pool->head; | |
pool->head = BLOCK_NEXT(pool->head, pool->info.block_size); | |
return block; | |
} | |
void memory_pool_free(memory_pool_t* pool, void* block) | |
{ | |
// Check block is in buffer range | |
BLOCK_NEXT(block, pool->info.block_size) = pool->head; | |
pool->head = block; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stddef.h> // size_t | |
typedef unsigned long u32; | |
typedef struct | |
{ | |
size_t block_size; | |
size_t block_alignment; | |
u32 num_blocks; | |
} memory_pool_create_info_t; | |
typedef struct | |
{ | |
void* buffer; | |
void* head; | |
memory_pool_create_info_t info; | |
} memory_pool_t; | |
memory_pool_t* memory_pool_create(memory_pool_create_info_t const*); | |
void memory_pool_destroy(memory_pool_t*); | |
void* memory_pool_malloc(memory_pool_t*); | |
void memory_pool_free(memory_pool_t*, void*); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment