Custom Memory Management in C++
Memory Management:
Process in which memory allocation and de-allocation to the variable in running program and handle overall performance.
Why need memory management?
Memory management is required to handle the available memory efficiently without any wastage and efficient de-allocation.
?In the c++ program, memory is divided into many parts. Mainly Stack and heap memory. Stack is to hold variables used inside the program and other information related to function. Heap is unused memory and allocate dynamically while running the program.
Scenario: Let's consider that I have a requirement of 30 INT size memory in the current execution and I have required?10 more INT size memory for computation. But I have allocated 30 INT size memory in static space but after execution, if I required 10 INT size memory I have to re-calculate and re-assignment of complete array. Or if I required only 10 INT size memory for execution, then the remaining 20 INT size memory gets wasted in program execution.
?There are multiple such scenarios of dynamic nature. So required dynamic allocation of memory based on requirements in the run time of the program. Hence Heap plays a very crucial role and memory management is also very important in such situations. Program releases the memory back to heap once the usage of memory got completed.
Heap memory is completely managed by the underlying operating system, But c++ creates an abstraction to handle the allocation and deallocation called a free store along with operation new() and delete().
领英推荐
?In some cases, like bare metal platforms where there is no operating system, there we can not directly use the c++ base abstraction to handle memory allocation and deallocation process. In such cases, a custom memory management application is required.?That we can call "Custom Heap".
Customized Heap:
We can define the required memory slot in BSS or directly in RAM.?This is marked as a heap memory location. Define some custom allocation and deallocation operations which acquire and release memory from specified regions respectively. We have to keep track of the free space and allocated space and re-arrangement de-allocated spaces. In such criteria, need an internal data container like a linked list to handle allocation and deallocation details.
?Let's consider a acquire() operation to allocate memory from the region and It will try to find the best place that suits for required size in the linked list. If not there then it allocates at end of the allocation list.
Example Code:
/
* This is program to illustrate about the custom Heap allocation
*/
#include <iostream>
#include <iomanip>
using namespace std;
struct MemoryInformation
{
struct MemoryInformation *next;
size_t size; // size of allocation
bool isFree; // checking flag whether it free or busy in allocation status
};
class CustomHeap
{
private:
struct MemoryInformation *root; // root node of memory informaiton handler
char *EndOfCustomMemory;
CustomHeap(); // private constructor to handle the single object
static void *operator new(size_t size); // custom new opeation to handle allocation
void setupRootNode();
public:
~CustomHeap();
void clearCustomHeap();
void *acquireCustomMemory(size_t size); // utility to acquire memory from the custom location
bool releaseCustomMemory(void *memoryObject); // utility to release allocated memory back to free store
static void customMemoryDump(); // utility to provide the custom memory information in readble format
static CustomHeap *getCustomHeapInstance(); // singleton class object to handle acquire and release operations
};
static const size_t MAX_CUSTOM_HEAP_SIZE = 10240;
static char customMemoryLayout[MAX_CUSTOM_HEAP_SIZE];
static char customMemoryObject[sizeof(CustomHeap)];
void CustomHeap::setupRootNode()
{
this->root = reinterpret_cast<MemoryInformation *>(&customMemoryLayout[0]);
this->root->next = nullptr;
this->root->isFree = true;
this->root->size = MAX_CUSTOM_HEAP_SIZE;
this->EndOfCustomMemory = &customMemoryLayout[MAX_CUSTOM_HEAP_SIZE - 1];
}
CustomHeap::CustomHeap()
{
cout << "\n CustomHeap::CustomHeap() started";
// step1: clear the pre-allocated memory
clearCustomHeap();
setupRootNode();
cout << "\n CustomHeap::CustomeHeap() completed";
}
CustomHeap::~CustomHeap()
{
clearCustomHeap(); // de-allocate before deleting the singleton object
cout << "\nCustomHeap::~CustomHeap()";
}
void CustomHeap::clearCustomHeap()
{
for (auto &itr : customMemoryLayout)
{
itr = static_cast<char>(0); // assign the allocation memory to zero in CustomMemoryLayout
}
return;
}
void *CustomHeap::acquireCustomMemory(size_t requiredSize)
{
// acquiring the memory layout
char *_memory = nullptr;
MemoryInformation *memoryBlockInfo = root; // assign the first root to iterate
do
{
// This check helps to identify the block size and free locations
if (memoryBlockInfo->isFree && memoryBlockInfo->size >= requiredSize)
{
// 1. found the free location to store values into memory - allocate memory block
_memory = reinterpret_cast<char *>(memoryBlockInfo + 1);
// 2. updating the memory block informations
memoryBlockInfo->size = requiredSize;
memoryBlockInfo->isFree = false;
// 3. Now, need to update the next memory block information and update the memory list
if (memoryBlockInfo->next != nullptr)
{
MemoryInformation *temp = reinterpret_cast<MemoryInformation *>(memoryBlockInfo->next);
// checking the memory size that can fit inbetween the list
size_t remainingSize = size_t(((size_t)temp) - (((size_t)(_memory + requiredSize)) + ((size_t)1)));
if (remainingSize > sizeof(MemoryInformation))
{
MemoryInformation *newMemObj = reinterpret_cast<MemoryInformation *>(_memory + requiredSize);
newMemObj->next = temp;
newMemObj->isFree = true;
newMemObj->size = remainingSize - sizeof(MemoryInformation);
memoryBlockInfo->next = newMemObj;
}
// if not we can allocate the memory block here to acquire
}
else if (size_t(_memory) + requiredSize < size_t(EndOfCustomMemory))
{
// checking the future custom memory end location
size_t remaingEndSize = size_t(EndOfCustomMemory) - (size_t(_memory) + requiredSize) + size_t(1);
if (remaingEndSize > sizeof(MemoryInformation))
{
MemoryInformation *newMemObj = reinterpret_cast<MemoryInformation *>(_memory + requiredSize);
newMemObj->next = nullptr;
newMemObj->isFree = true;
newMemObj->size = remaingEndSize - sizeof(MemoryInformation);
memoryBlockInfo->next = newMemObj;
}
}
break;
}
memoryBlockInfo = memoryBlockInfo->next;
} while (memoryBlockInfo != nullptr);
return reinterpret_cast<void *>(_memory);
}
bool CustomHeap::releaseCustomMemory(void *_memory)
{
char *mem = reinterpret_cast<char *>(_memory);
bool releaseStatus = false;
if ((unsigned int)(size_t)(mem) < (unsigned int)(size_t)(customMemoryLayout))
{
std::cout << "\n[Error]: Invalid memory access";
return releaseStatus;
}
MemoryInformation *memoryBlockInfo = root;
MemoryInformation *requiredMemoryBlock = reinterpret_cast<MemoryInformation *>(mem) - 1;
do
{
if (memoryBlockInfo == requiredMemoryBlock)
{
cout << "\n[Log]: Found the release memory slot";
memoryBlockInfo->isFree = true;
for (int i = 0; i < memoryBlockInfo->size; i++)
{
mem = nullptr; // assign the zero's to memory block
}
releaseStatus = true;
break;
}
memoryBlockInfo = memoryBlockInfo->next;
} while (memoryBlockInfo != nullptr);
}
void CustomHeap::customMemoryDump()
{
int index;
cout << "\n Custom Memory Layout Details:";
for (auto byte : customMemoryLayout)
{
cout << "\n Byte - " << dec << index << ":" << hex << "0x" << (0xFF & (unsigned int)byte) << endl;
}
cout << "\n";
}
void *CustomHeap::operator new(size_t size)
{
return reinterpret_cast<void *>(customMemoryObject);
}
CustomHeap *CustomHeap::getCustomHeapInstance()
{
static bool init = false;
static CustomHeap *heapObj = nullptr;
if (init == false)
{
heapObj = new CustomHeap();
init = true;
}
return heapObj;
}
// Let try to create a class and allocate memory from the custom Heap
class Base
{
private:
int value;
public:
explicit Base(int input = 0) : value(input)
{
cout << "\n Creation of Base(): " << dec << value << endl;
}
~Base()
{
cout << "\n Destructor of Base()" << endl;
}
static void *operator new(size_t size)
{
cout << "\n Custom Heap allocation size: " << size << endl;
CustomHeap *heap = CustomHeap::getCustomHeapInstance();
void *_memory = heap->acquireCustomMemory(size);
}
static void operator delete(void *mem)
{
cout << "\n Deletion of allocation memory" << endl;
CustomHeap *heap = CustomHeap::getCustomHeapInstance();
heap->releaseCustomMemory(mem);
return;
}
};
int main()
{
// Pointer to hold the custom Heap Memory allocation
char *memoryAllocation1;
char *memoryAllocation2;
char *memoryAllocation3;
char *memoryAllocation4;
char *memoryAllocation5;
CustomHeap *heap = CustomHeap::getCustomHeapInstance();
memoryAllocation1 = reinterpret_cast<char *>(heap->acquireCustomMemory(200));
// checking the allocation status
if (memoryAllocation1 != nullptr)
{
cout << "\n Successful Allocation of Custom Heap at index: " << hex << (unsigned int)(size_t)memoryAllocation1 << endl;
// use the allocated memory
for (int i = 0; i < 200; i++)
{
memoryAllocation1 = (char *)(i);
}
memoryAllocation2 = reinterpret_cast<char *>(heap->acquireCustomMemory(100));
if (memoryAllocation2 != nullptr)
{
cout << "\n Successful Allocation of Custom Heap at index: " << hex << (unsigned int)(size_t)memoryAllocation2 << endl;
for (int i = 0; i < 100; i++)
{
memoryAllocation2 = (char *)(i);
}
}
else
{
cout << "\n[Error]: Failed to Allocate Custom Heap Memory" << endl;
}
}
// CustomHeap::customMemoryDump();
// now check the de-allocation of memory
if (heap->releaseCustomMemory(memoryAllocation2))
{
cout << "\n[Info]: Successful release of allocated memory";
}
else
{
cout << "\n[Error]: Failed to release of allocated memory";
}
return 0;
}
Please provide your inputs.