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.

要查看或添加评论,请登录

Shrikant Badiger的更多文章

  • NVMe Over TCP

    NVMe Over TCP

    NVMe over TCP is enhanced feature of NVMe over Fabrics. It used the standard network stack(Ethernet) without any…

    1 条评论
  • Bazel Build for C++ Software Application

    Bazel Build for C++ Software Application

    Bazel Tool is developed by google to automate the build process. Now It's an open source and it can be used by anyone.

  • C++ Class Layout

    C++ Class Layout

    Class Layout: Only non-static data members will contribute to the size of the class object. If we have static and…

    1 条评论
  • High-performance Computing in C++ : Open Muti Processing(OpenMP)

    High-performance Computing in C++ : Open Muti Processing(OpenMP)

    Open Multi-Processing: Let's consider the parallelization approaches, basically, we can think of imperative…

  • High-performance Computing in C++

    High-performance Computing in C++

    Single Instruction Multiple Data (SIMD) Multiple core CPUs and Multithreading: Declarative(OpenMP), imperative…

  • vSocket Interface - Guest to Host Communication

    vSocket Interface - Guest to Host Communication

    vSocket: VMware vSocket provides a very similar API to the Unix Socker interface for communication. vSocket library is…

  • Pointers in C

    Pointers in C

    Pointers in C: Pointers are fundamental parts of C Programming. Pointers provide the lots of power and flexibility in C…

  • CMake and Useful Info

    CMake and Useful Info

    CMake is an open-source tool to build, test, and package software applications. CMake provides control over the…

    1 条评论
  • Interrupt !!

    Interrupt !!

    Processors need to detect hardware activities. There are multiple solutions to detect hardware activities.

  • PXE: Preboot Execution Environment

    PXE: Preboot Execution Environment

    PXE: Preboot Execution Environment. Technology helps computers to boot up remotely through a network interface.

社区洞察

其他会员也浏览了