C++ メモリ プール (1) 理論的基礎と簡単な実装

1. メモリプールの原理

1. まず実際の例を使って、メモリ プールとは何かを説明しましょう。
    (1) 毎月の末にお金が足りなくなったとき、または緊急にお金が必要になったとき、両親に電話してお金を借りてもらいます。あなたの両親は WeChat または Alipay 経由であなたに送金してお金を渡します。このように、お金が必要になるたびに親に連絡し、親がお金をくれるということは、大学4年間を経て間違いなく膨大な時間とエネルギーを消費することになります。
    (2) 親が一度に多額のお金をくれるので、それを好きなだけ使っていい。これは間違いなくはるかに便利で、メモリ プール方法に似ています。
    そこで、実際にメモリを使用する前に、あらかじめ設定されたサイズのメモリブロックを一定数割り当て申請しておこうというのがメモリプールの考え方です。新たなメモリ需要が発生した場合、メモリプールからメモリブロックの一部が割り当てられ、メモリブロックが不足する場合は引き続き新たなメモリが適用され、メモリが解放されるとメモリプールに戻されます。その後の再利用のために。これによりメモリの使用効率が向上し、一般に制御不能なメモリの断片化が発生しなくなります。
2. では、C++ で特定のスレッド プールを実装するにはどうすればよいでしょうか? 簡単に言えば、次の手順が必要です。
    (1) まず、連続メモリ空間を申請します。
    (2) メモリ ノード: 1 つのデータ オブジェクトと次のデータ オブジェクトへのポインタが含まれます。各空きメモリ ノードは、ポインタを介してリンク リストを形成し、リンク リスト内の各メモリ ノードは、割り当てに使用できるメモリ空間の一部です。
    (3) メモリ ノードが割り当てられると、そのメモリ ノードは空きメモリ ノード リストから削除されます。
    (4) メモリノードを解放したら、空きメモリノードリストに再度メモリノードを追加します。
    (5) メモリ ブロックのすべてのメモリ ノードが割り当てられている場合、プログラムが引き続き新しいオブジェクト空間を申請すると、新しいオブジェクトを収容するために再度メモリ ブロックを申請します。新しく適用されたメモリ ブロックは、メモリ ブロックのリンク リストに追加されます。

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

3. 完全なコード

1、メモリプール.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、メモリプール.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;
}

おすすめ

転載: blog.csdn.net/mars21/article/details/132899847