C++内存池(1)理论基础及简单实现

一、内存池原理

1、我们先用生活中的例子来解释什么是内存池:
    (1)每个月月底钱花完时,或者急需要用钱时,你就打电话给你父母要钱,然后父母把钱通过微信或支付宝转给你。这种方式,每次要用钱时就需要联系你父母,然后你父母再把钱给你,4年大学下来,这里面耗费的时间也精力肯定不少。
    (2)父母一次性给你一大笔钱,你随便用随便花。这样肯定方便多了,这就类似内存池方式。
    所以内存池的思想,就是在真正使用内存之前,预先申请分配一定数量、大小预设的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存,当内存释放后就回归到内存池留作后续的复用。使得内存使用效率得到提升,一般也不会产生不可控制的内存碎片。
2、那么在C++中怎么实现具体的线程池呢?简单地说,需要下面这几个步骤:
    (1)先申请一块连续的内存空间。
    (2)内存节点:含1个数据对象和指向下一个数据对象的指针。每个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。
    (3)某个内存节点一旦分配出去,从空闲内存节点链表中移除。
    (4)某个内存节点一旦被释放,将该内存节点重新加入空闲内存节点链表。
    (5)如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。

二、用C++实现内存池

1、定义一个内存节点

template<typename T>
struct Node{
    T data;         // 元素
    Node<T>* next;  // 指向下一个节点的指针
};

2、初始化1个内存块

//当前没有空闲节点
if(this->pMemoryHead == nullptr){
    this->pMemoryHead = new Node<T>; //生成新节点
        
    Node<T> *pTemp = this->pMemoryHead; //将数据连接起来
    for(int i = 1; i < blockSize; i++){
         pTemp->next = new Node<T>;
         pTemp = pTemp->next;
    }
    pTemp->next = nullptr;
        
    this->headCount += blockSize; //可用内存节点数
}

3、申请1个对象空间

Node<T> *pTemp = this->pMemoryHead;
pMemoryHead = pMemoryHead->next; //指向下一个未使用的节点

//因为temp指向的是当前将被使用的节点, 把它的next指向前面的被使用节点
pTemp->next = pUsedHead;
pUsedHead = pTemp; //指针指向最新将被使用的节点
this->headCount--;
this->usedCount++;

4、释放对象空间

Node<T> *pFree = (_Node<T>*)p; //释放的节点
Node<T> *pTemp = pUsedHead;

//第一种情况    
if(pTemp == pFree){  //第一个就是

      pUsedHead = pUsedHead->next;
      pTemp->next = pMemoryHead; //将节点重新接到MemoryHead
      pMemoryHead = pTemp;
      
      this->usedCount--;
      this->headCount++;
      
      return;
}

//第二种情况
Node<T> *prev;
while(pTemp != nullptr){        
    if(pTemp == pFree){    
        prev->next = pTemp->next;
        pTemp->next = MemoryHead;
        MemoryHead = pTemp;
            
        this->usedCount--;
        this->headCount++;

        return;
    }
    //前一个节点
    prev = pTemp;
        

    //查询下一个节点
    pTemp = pTemp->next;
}

三、完整代码

1、MemoryPool.h

#include <iostream>
#include <list>
#include <string>

using namespace std;

template<typename T>
struct Node{        //节点
    T data;         //元素
    Node<T>* next;  //指向下一个节点的指针
};

template <typename T, int blockSize = 10>
class MemoryPool{
public:
    MemoryPool();
    ~MemoryPool();
    
    void* allocate();
    int free(void *p);

    int headCount;
    int usedCount;

private:  
    Node<T>* pMemoryHead;  //未使用的节点
    Node<T>* pUsedHead;    //正在使用的节点
};

2、MemoryPool.cpp

#include"MemoryPool.h"
#include<vector>

template <class T, int blockSize>
MemoryPool<T, blockSize>::MemoryPool(){
     this->pMemoryHead = nullptr;
     this->pUsedHead = nullptr;

     this->headCount = 0;
     this->usedCount = 0;
}

template <class T, int BlockSize>
MemoryPool<T, blockSize>::~MemoryPool(){
  Node<T>* ptr;
	while(this->pMemoryHead){
		ptr = this->pMemoryHead->next;
		delete this->pMemoryHead;
		pMemoryHead = ptr;
	}

	while (this->pUsedHead){
		ptr = this->pUsedHead->next;
		delete this->pUsedHead;
		pUsedHead = ptr;
	}
}

template <class T, int blockSize>
void* MemoryPool<T, blockSize>::allocate(){
    if(this->pMemoryHead == nullptr){
        //当没有空闲节点
        this->pMemoryHead = new Node<T>;

        Node<T> *pTemp = this->pMemoryHead;   //将数据连接起来
        for(int i = 1; i < blockSize; i++){
             pTemp->next = new Node<T>;
             pTemp = pTemp->next;
        }
        pTemp->next = nullptr;
        
        this->headCount += blockSize;
    }

    Node<T> *pTemp = pMemoryHead;
    pMemoryHead = pMemoryHead->next;  //指向下一个数据节点

    //将data 挂在到UseHead
    pTemp->next = pUsedHead;
    pUsedHead = pTemp;
    this->headCount--;
    this->usedCount++;

    return reinterpret_cast<void*>(pTemp);
}

template <typename T, int blockSize>
int MemoryPool<T, blockSize>::free(void *p){
     //遍历 UsedHead链表
    Node<T> *pFind = (Node<T>*)p;
    Node<T> *pTemp = pUsedHead;

    if(pTemp == pFind){  //第一个就是
      pUsedHead = pUseHead->next;
      pTemp->next = pMemoryHead;   //将节点重新接到MemoryHead
      pMemoryHead = pTemp;
      
      this->usedCount--;
      this->headCount++;

      return 1;
    }
    
    Node<T> *prev;
    while(pTemp != nullptr){
        if(pTemp == pFind){
            prev->next = pTemp->next;
            pTemp->next = pMemoryHead;
            pMemoryHead = pTemp;

            this->usedCount--;
            this->headCount++;

            return 1;
        }
        
        prev = pTemp;
        // 查下一个节点
        pTemp = pTemp->next;
    }

    return -1;
}

int main(){
    MemoryPool<int, 100> pa;
    vector<int*> ret;
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;
    for(int i=0;i<50;i++){
        ret.push_back(reinterpret_cast<int*>(pa.allocate()));
    }
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;

    for(int i=0;i<10;i++){
        pa.free(reinterpret_cast<void*>(ret[i]));
    }
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值