Skip to content

Instantly share code, notes, and snippets.

@diffstorm
Created August 13, 2023 13:51
Show Gist options
  • Save diffstorm/6b0f2f4ca1fdf7a29270f55fb57d4f86 to your computer and use it in GitHub Desktop.
Save diffstorm/6b0f2f4ca1fdf7a29270f55fb57d4f86 to your computer and use it in GitHub Desktop.
Static memory allocator for embedded systems in C++ with auto fragmentation where malloc/new is unwanted
/*
Static memory allocator for embedded systems in C++ with auto fragmentation where malloc/new is unwanted
Author : Eray Ozturk | [email protected]
*/
#include <iostream>
#include <cstddef>
class StaticMemoryAllocator {
public:
StaticMemoryAllocator(char* buffer, size_t bufferSize) : buffer_(buffer), bufferSize_(bufferSize), head_(nullptr) {
BlockHeader* initialBlock = reinterpret_cast<BlockHeader*>(buffer_);
initialBlock->size = bufferSize_ - sizeof(BlockHeader);
initialBlock->next = nullptr;
head_ = initialBlock;
}
~StaticMemoryAllocator() {
// Deallocate all memory blocks when the allocator instance is destroyed
BlockHeader* curr = head_;
while (curr) {
BlockHeader* next = curr->next;
curr->size = 0;
curr->next = nullptr;
curr = next;
}
}
void* allocate(size_t size) {
if (size == 0 || size > bufferSize_) {
return nullptr; // Invalid size
}
BlockHeader* prev = nullptr;
BlockHeader* curr = head_;
while (curr) {
if (curr->size >= size) {
// Allocate from the current block
if (curr->size > size + sizeof(BlockHeader)) {
// Split the block
BlockHeader* newBlock = reinterpret_cast<BlockHeader*>(reinterpret_cast<char*>(curr) + sizeof(BlockHeader) + size);
newBlock->size = curr->size - size - sizeof(BlockHeader);
newBlock->next = curr->next;
curr->size = size;
curr->next = newBlock;
}
// Update the free list
if (prev) {
prev->next = curr->next;
} else {
head_ = curr->next;
}
return reinterpret_cast<char*>(curr) + sizeof(BlockHeader);
}
prev = curr;
curr = curr->next;
}
return nullptr; // Not enough memory
}
void deallocate(void* ptr) {
if (ptr >= buffer_ && ptr < buffer_ + bufferSize_) {
BlockHeader* block = reinterpret_cast<BlockHeader*>(static_cast<char*>(ptr) - sizeof(BlockHeader));
block->next = head_;
head_ = block;
}
}
void print() {
std::cout << "Memory Blocks:" << std::endl;
BlockHeader* curr = head_;
while (curr) {
std::cout << "Size: " << curr->size << " bytes" << std::endl;
curr = curr->next;
}
}
private:
struct BlockHeader {
size_t size;
BlockHeader* next;
};
char* buffer_;
size_t bufferSize_;
BlockHeader* head_;
};
int main() {
constexpr size_t bufferSize = 1024;
char memoryBuffer[bufferSize];
StaticMemoryAllocator memoryAllocator(memoryBuffer, bufferSize);
// Allocate int
int* intPtr = static_cast<int*>(memoryAllocator.allocate(sizeof(int)));
if (intPtr) {
*intPtr = 42;
std::cout << "Allocated int: " << *intPtr << std::endl;
memoryAllocator.print();
} else {
std::cout << "Memory allocation failed" << std::endl;
}
// Allocate a double block
double* doublePtr = static_cast<double*>(memoryAllocator.allocate(sizeof(double)));
if (doublePtr) {
*doublePtr = 3.14;
std::cout << "Allocated double: " << *doublePtr << std::endl;
memoryAllocator.print();
} else {
std::cout << "Memory allocation failed" << std::endl;
}
// Deallocate the int block
if (intPtr) {
memoryAllocator.deallocate(intPtr);
intPtr = nullptr;
std::cout << "Deallocated int" << std::endl;
memoryAllocator.print();
}
// Allocate a larger block
char* charPtr = static_cast<char*>(memoryAllocator.allocate(256));
if (charPtr) {
std::cout << "Allocated 256 bytes" << std::endl;
memoryAllocator.print();
} else {
std::cout << "Memory allocation failed" << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment