内存池与内存块

Posted masteryan576356467

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存池与内存块相关的知识,希望对你有一定的参考价值。

#include <iostream>
using namespace std;

constexpr int MEMORYPOOL_ALIGNMENT = 8;                        //对齐长度

// 内存块
template<typename _T>
struct MemoryBlock {
    int          nSize;                     //内存块大小,以字节为单位
    int          nFree;                     //内存块剩余可分配单位
    int          nFirst;                    //首个剩余单位序号
    MemoryBlock* pNext;                     //指向下一个内存块的指针
    char         aData[1];                  //内存空间开始位置标记

    //constructor
    MemoryBlock(int nUnitSize,               // 存储单位大小,sizeof T
                int nUnitAmount) :              // 内存块规模,以 存储单位 为单位计算
                nSize(nUnitAmount * nUnitSize), nFree(nUnitAmount - 1), nFirst(1), pNext(nullptr) {
                    //第一个单位在调用构造函数时分配,故nFree需要减1
                    //下一个可分配单位序号记录于当前单元的前两个字节
                    char *ppDate = aData;
                    cout << "the head ptr of memory ppDate = " << (int)*ppDate << endl;
                    for(int i = 1; i < nUnitAmount; ++i) {
                        //在 当前存储单位存储下一个可分配单位的序号
                        (*(uint16_t*)ppDate) = i;//short --- 16
                        cout << "the next available of memory is :" << (int)*ppDate << endl;
                        ppDate += nUnitSize; //指向下一个单位
                    }
                    cout << "===========================call MemoryBlock constructor ";
                }

    // overload 
    void* operator new(size_t, int nUnitSize, int nUnitAmount) {
        //内存空间长度为memoryBlock对象加存储空间总长度
        return ::operator new(sizeof(MemoryBlock) + nUnitAmount * nUnitSize);
    }

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

};

// 内存池
template<typename _T>
struct MemoryPool {
    int             nInitSize; //第一次分配大小
    int             nGrowSize; //增量大小
    int             nUnitSize; // 存储单位大小
    MemoryBlock<_T> *pBlock;

    MemoryPool(int _nGrowSize = 10, int _nInitSize = 3) 
        : nInitSize(_nInitSize), nGrowSize(_nGrowSize), pBlock(nullptr), nUnitSize(sizeof(_T)) {
        cout << "==========================call MemoryPool constructor ";
        //存储块大小调整
        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 ";
    }

    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;
            }
            //找到合适的内存块
            MemoryBlock<_T> *pMyBlock = pBlock;
            while(pMyBlock != nullptr && pMyBlock->nFree == 0) pMyBlock = pMyBlock->pNext;
            if(pMyBlock != nullptr) {
                cout << "找到内存空间, first = " << pMyBlock->nFirst << endl;
                char *pFree = pMyBlock->aData + pMyBlock->nFirst * nUnitSize;
                pMyBlock->nFirst = *((uint16_t *)pFree);
                pMyBlock->nFree--;
                return (void *)pFree;
            }
            else {
                //没有找到,说明内存块已经用完
                if(nGrowSize == 0) return NULL;
                cout << "allocate new memoryBlock ";
                pMyBlock = (MemoryBlock<_T>*) new (nUnitSize, nGrowSize) MemoryBlock<_T> (nUnitSize, nGrowSize);
                //失败返回
                if(pMyBlock == nullptr) return NULL;
                //成功的话插入链表
                pMyBlock->pNext = pBlock;
                pBlock = pMyBlock;
                return (void *)pMyBlock->aData;
            }
        }



    }

    void free(void *pFree) {
        cout << "relese room ";
        //找到内存块
        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) {
            //修改数组链表
            *((uint16_t*)pFree) = pMyBlock->nFirst;
            pMyBlock->nFirst = (uint16_t)((uint32_t)pFree - (uint32_t)pMyBlock->aData) / nUnitSize;
            pMyBlock->nFree++;
        
            //是否需要向OS释放内存
            if(pMyBlock->nSize == pMyBlock->nFree * nUnitSize) {
                //delete node
                delete pMyBlock;
            }
            else {
                //将block插入队首
                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 ";
    }

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

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;
}



以上是关于内存池与内存块的主要内容,如果未能解决你的问题,请参考以下文章

简单内存池与定长内存池

源码解读·RT-Thread操作系统内存管理之内存池

STL源码剖析——空间配置器Allocator#3 自由链表与内存池

线程池与锁优化

GIL 线程池与进程池 同步与异步

内存池进程池线程池