Memory block and the memory pool

#include <iostream>
using namespace std;

constexpr int MEMORYPOOL_ALIGNMENT = 8; // length aligned

// memory block
template<typename _T>
struct MemoryBlock {
    int nSize; // memory block size, in bytes
    int nFree; // allocate a block of memory units Remaining
    int nFirst; // first unit remaining number
    MemoryBlock * pNext; // pointer to point to a next memory block
    char aData [1]; // tag memory start position

    //constructor
    MemoryBlock (int nUnitSize, // storage unit size, sizeof T
                int nUnitAmount): // size of the memory block to store the unit for computing
                nSize(nUnitAmount * nUnitSize), nFree(nUnitAmount - 1), nFirst(1), pNext(nullptr) {
                    // first unit assigned when calling the constructor, it is a need to reduce the nFree
                    // next unit can be assigned a sequence number recorded in the first two bytes of the current unit
                    char * = ppDate aData;
                    cout << "the head ptr of memory ppDate = " << (int)*ppDate << endl;
                    for(int i = 1; i < nUnitAmount; ++i) {
                        // can be assigned a number of units currently stored in the storage unit
                        (*(uint16_t*)ppDate) = i;//short --- 16
                        cout << "the next available of memory is :" << (int)*ppDate << endl;
                        ppDate + = nUnitSize; // pointer to the next unit
                    }
                    cout << "===========================call MemoryBlock constructor\n";
                }

    // overload 
    void* operator new(size_t, int nUnitSize, int nUnitAmount) {
        // length memoryBlock memory space plus the total length of the object storage space
        return ::operator new(sizeof(MemoryBlock) + nUnitAmount * nUnitSize);
    }

    void operator delete(void *pBlock) {
        ::operator delete(pBlock);
        cout << "================================call MemoryBlock destructor\n";
    }

};

// memory pool
template<typename _T>
struct MemoryPool {
    int nInitSize; // allocation size for the first time
    int nGrowSize; // increment size
    int nUnitSize; // storage unit size
    MemoryBlock<_T> *pBlock;

    MemoryPool(int _nGrowSize = 10, int _nInitSize = 3) 
        : nInitSize(_nInitSize), nGrowSize(_nGrowSize), pBlock(nullptr), nUnitSize(sizeof(_T)) {
        cout << "==========================call MemoryPool constructor\n";
        // memory block sizing
        auto _size = sizeof(_T);
        if(_size > 4) {
            nUnitSize = (_size + MEMORYPOOL_ALIGNMENT - 1) & ~(MEMORYPOOL_ALIGNMENT - 1);
        }
        else if(_size < 2) {
            nUnitSize = 2;
        }
        else
            nUnitSize = 4;
    }

    ~MemoryPool() {
        MemoryBlock<_T> * pMyBlock = pBlock;
        while(pMyBlock != nullptr) {
            pMyBlock = pMyBlock->pNext;
            delete pMyBlock;
        }
        cout << "================================call MemoryPool destructor\n";
    }

    void *allocate(size_t num) { //typename Allocator<_T>::const_pointer hint = 0
        for(int i = 0; i < num; ++i) {
            if(pBlock == nullptr) {
                //create memoryBlock
                pBlock = (MemoryBlock<_T>*) new (nUnitSize, nInitSize) MemoryBlock<_T>(nUnitSize, nInitSize);

                return (void *)pBlock->aData;
            }
            // find the right memory block
            MemoryBlock<_T> *pMyBlock = pBlock;
            while(pMyBlock != nullptr && pMyBlock->nFree == 0) pMyBlock = pMyBlock->pNext;
            if(pMyBlock != nullptr) {
                cout << "to find the memory space, first =" << pMyBlock-> nFirst << endl;
                char *pFree = pMyBlock->aData + pMyBlock->nFirst * nUnitSize;
                pMyBlock->nFirst = *((uint16_t *)pFree);
                pMyBlock->nFree--;
                return (void *)pFree;
            }
            else {
                // not found, indicating that the memory block has been exhausted
                if(nGrowSize == 0) return NULL;
                cout << "allocate new memoryBlock\n";
                pMyBlock = (MemoryBlock<_T>*) new (nUnitSize, nGrowSize) MemoryBlock<_T> (nUnitSize, nGrowSize);
                // failure to return
                if(pMyBlock == nullptr) return NULL;
                // successful in the linked list
                pMyBlock->pNext = pBlock;
                pBlock = pMyBlock;
                return (void *)pMyBlock->aData;
            }
        }



    }

    void free(void *pFree) {
        cout << "relese room\n";
        // find memory
        MemoryBlock<_T> * pMyBlock = pBlock;
        MemoryBlock<_T> * preBlock = nullptr;
        while (pMyBlock != nullptr && (pBlock->aData > pFree || pMyBlock->aData + pMyBlock->nSize)) {
            preBlock = pMyBlock;
            pMyBlock = pMyBlock->next;
        }
        //
        if(pMyBlock != nullptr) {
            // modify the array list
            *((uint16_t*)pFree) = pMyBlock->nFirst;
            pMyBlock->nFirst = (uint16_t)((uint32_t)pFree - (uint32_t)pMyBlock->aData) / nUnitSize;
            pMyBlock->nFree++;
        
            // need to free up memory to the OS
            if(pMyBlock->nSize == pMyBlock->nFree * nUnitSize) {
                // delete node
                delete pMyBlock;
            }
            else {
                // The block is inserted into the first team
                preBlock = pMyBlock->pNext;
                pMyBlock->pNext = nullptr;
                pBlock = pMyBlock;
            }
        } 
    }

};


class User {
    int s;
    double s1;
    double s3;
public:
    User(int x) : s(x) {
        cout << "*********************call User constructor\n";
    }

    int get() const { return s; };
    ~User() {
        cout << "************************call User destructor\n";
    }
};

int main () {
    
    MemoryPool<User> pool;
    User *dp1 = (User *)pool.allocate(1);
    cout << "dp1 = " << dp1 << endl;
    new (dp1) User (1111);
    cout << "the value of object is " << dp1->get() << endl;



    User *dp2 = (User *)pool.allocate(1);
    cout << "dp2 = " << dp2 << endl;
    new (dp2) User (2222);
    cout << "the value of object is " << dp2->get() << endl;


    User *dp3 = (User *)pool.allocate(1);
    cout << "dp3 = " << dp3 << endl;
    new (dp3) User (3333);
    cout << "the value of object is " << dp3->get() << endl;


    User *dp4 = (User *)pool.allocate(1);
    cout << "dp4 = " << dp4 << endl;
    new (dp4) User (4444);
    cout << "the value of object is " << dp4->get() << endl;


    User *dp5 = (User *)pool.allocate(1);
    cout << "dp5 = " << dp5 << endl;
    new (dp5) User (5555);
    cout << "the value of object is " << dp5->get() << endl;






    
    return 0;
}



Guess you like

Origin www.cnblogs.com/MasterYan576356467/p/12181530.html