C++ 實現(xiàn)一個簡易的內存池

下面是一個簡單的內存池思想的版本皆警,實現(xiàn)的思想如下:

  1. 通過維護一個freeNodeHeader鏈表爽彤。當要申請空間的時候,就從鏈表上面摘下一個結點诉植;要釋放一個空間的時候,就從將釋放的結點重新插入到鏈表里面昵观。

  2. 每個結點的大小是提前通過template傳入的倍踪,就是要分配的對象的大小。

Q1 : 為什么要寫一個內存池索昂,默認的malloc不挺好的嗎?
A1 :new 和 delete 是一個成本比較高的操作扩借,因為需要到堆上開辟和釋放空間椒惨。如果可以提前開辟好一大塊空間,然后潮罪,下次使用的時候康谆,就不需要可以直接使用內存池里面的空間,而不是去調用new和delete嫉到。這樣可以會更加高效沃暗。(使用線程池的目的也是這樣的)

Q2 : 自己設計的內存池會比malloc好嗎?會不會是負優(yōu)化?
A2 : 這個問題何恶,我也在思考孽锥。下面是我的思考(不一定是正確的答案)

  1. 自己設計內存池一定是基于一個特定的一個場景,如果在這個特定的場景下面,一個針對這個場景下設計出來的內存池也許會比默認的更好惜辑,但是如果這個場景是一個通用的場景唬涧,那我覺得默認的也許是更好的。
    就像使用STL一樣盛撑,如果知道了里面存放的元素是int碎节,然后知道了元素數(shù)量,知道了對元素常用的操作抵卫。那么完全可以設計出一個比STL更高效的函數(shù)狮荔。但是如果這是一個通用的,可以大范圍被使用的場景介粘,那么可能STL是平均下來最好的結果殖氏。

  2. 作為一個初學者,了解內存池的工作原理碗短,可以更好的理解一門編程語言的內存分配機制受葛。這對深入的學習非常有必要。我覺得還是應該學習學習的偎谁。哪怕你寫的內存池是一個垃圾总滩。

#include <iostream>
using namespace std;

template<int ObjectSize, int NumofObjects = 20>   
class MemPool {
private:
    struct FreeNode {
        FreeNode* pNext;
        char data[ObjectSize];
    };

    FreeNode * freeNodeHeader;     //表示空閑鏈表
public:
    MemPool() {
        //init freeNodeHeader
        this->freeNodeHeader = new FreeNode[NumofObjects];
        for (int i = 0; i < NumofObjects - 1; i++) {
            freeNodeHeader[i].pNext = &freeNodeHeader[i + 1];
        }
        freeNodeHeader[NumofObjects-1].pNext = NULL;

    }

    ~MemPool() {
        cout << " ~ 析構函數(shù) " << endl;
        delete[] freeNodeHeader;
    }

    //函數(shù)的實現(xiàn)在下面
    void* malloc() {
        if (freeNodeHeader==NULL) {  //空間沒有了
            //分配一段新的空間
            cout << "重新添加了空間" << endl;
            FreeNode * newfreeNodeHeader = new FreeNode[NumofObjects];
            for (int i = 0; i < NumofObjects - 1; i++) {
                newfreeNodeHeader[i].pNext = &newfreeNodeHeader[i + 1];
            }
            newfreeNodeHeader[NumofObjects-1].pNext = NULL;   
            
            //于是又有了空間
            freeNodeHeader = newfreeNodeHeader;
        }
        cout << "分配一個空間" << endl;
        FreeNode * ret = freeNodeHeader;
        freeNodeHeader = freeNodeHeader->pNext;
        ret->pNext = NULL;
        return ret;
    }

    void free(void* p) {
        cout << "釋放一個空間" << endl;
        FreeNode* pNode = (FreeNode*)p;
        pNode->pNext = freeNodeHeader;//將釋放的節(jié)點插入空閑節(jié)點頭部
        freeNodeHeader = pNode;
    }
};

//一個實例類,用來作為測試
class ActualClass {
    static int count;
    int No;

public:
    ActualClass() {
        No = count;
        count++;
    }

    void print() {
        cout << this << ": ";
        cout << "the " << No << " object" << endl;
    }

    void* operator new(size_t size);
    void operator delete(void* p);


    void* operator new[](size_t size);
    void operator delete[](void *p,size_t size);
};

MemPool<4, 5> mp;

void* ActualClass::operator new(size_t size) {
    cout << "size " << size << endl;
    return mp.malloc();
}

void ActualClass::operator delete(void* p) {
    mp.free(p);
}

void* ActualClass::operator new[](size_t size) {
    cout << "size " << size << endl;
    cout << "自定義的內存池并不支持申請多個空間,所以調用默認的malloc" << endl;
    return malloc(size);
}

void ActualClass::operator delete[](void *p , size_t size)
{
    cout << "調用默認的free" << endl;
    cout<<"delete [] size : "<<size<<endl;
    free(p);
}

int ActualClass::count = 0;



int main()
{
    for (int i = 0; i < 3; i++) {
        ActualClass* p = new ActualClass;
        p->print();
    }

    ActualClass* p1 = NULL;
    p1 = new ActualClass;
    p1->print();

    ActualClass* p2 = new ActualClass;
    p2->print();

    delete(p1);

    ActualClass* p3 = new ActualClass;
    p3->print();

    //to-do
    //目前內存池只能分配固定大小的空間巡雨,
        //對于new[5] , 他申請內存的大小是 5*sizeof(ActualClass) + 4 
        // 但是實現(xiàn)的內存池只能分配固定大小闰渔,于是就使用malloc分配了
        ActualClass* p4 = new ActualClass[5];
    delete [] p4;
        //ActualClass* p5 = new ActualClass[5];
    //ActualClass* p6 = new ActualClass[5];

    system("pause");
    return 0;
};

分享另外一個版本:

基本的實現(xiàn)是和上面的一個相同的:


#include <iostream>
#include <windows.h>

using namespace std;

#include "MemoryPool.h"
#include "MTMemoryPool.h"

class CTest
{
public:
    int m_n;
    int m_n1;

    void* operator new(size_t size)
    {
        void* p = s_pool->Alloc(size);
        return p;
    }

    void operator delete(void* p, size_t size)
    {
        s_pool->Free(p);
    }

    static void NewPool()
    {
        s_pool = new CMemoryPool<CTest>;
        //s_pool = new CMTMemoryPool<CMemoryPool<CTest>, CCriticalSection>;
    }

    static void DeletePool()
    {
        delete s_pool;
        s_pool = NULL;
    }

    static CMemoryPool<CTest>* s_pool;
    //static CMTMemoryPool<CMemoryPool<CTest>, CCriticalSection>* s_pool;
};

CMemoryPool<CTest>* CTest::s_pool = NULL;
//CMTMemoryPool<CMemoryPool<CTest>, CCriticalSection>* CTest::s_pool = NULL;

void testFun()
{
    int i;
    const int nLoop = 10;
    const int nCount = 10000;

    for (int j = 0; j<nLoop; ++j)
    {
        typedef CTest* LPTest;
        LPTest arData[nCount];
        for (i = 0; i <nCount; ++i)
        {
            arData[i] = new CTest;
        }

        for (i = 0; i <nCount; ++i)
        {
            delete arData[i];
        }
    }
}

int main(int argc, char* argv[])
{
    {
        unsigned int dwStartTickCount = GetTickCount();

        CTest::NewPool();

        testFun();

        CTest::DeletePool();

        cout << "total cost" << GetTickCount() - dwStartTickCount << endl;
    }


    system("pause");

    return 0;
    
}

//http://www.cppblog.com/weiym/archive/2012/05/05/173785.html

Memory.h

template<typename T>   //這里的T指的是 : CTest類
class CMemoryPool
{
private:
    CMemoryPool<T>* m_pFreeList;

public:
    enum { EXPANSION_SIZE = 32 };

    CMemoryPool(unsigned int nItemCount = EXPANSION_SIZE)
    {
        ExpandFreeList(nItemCount);
    }

    ~CMemoryPool()
    {
        //free all memory in the list
        CMemoryPool<T>* pNext = NULL;
        for (pNext = m_pFreeList; pNext != NULL; pNext = m_pFreeList)
        {
            m_pFreeList = m_pFreeList->m_pFreeList;
            delete[](char*)pNext;
        }
    }

    void* Alloc(unsigned int /*size*/)
    {
        if (m_pFreeList == NULL)
        {
            ExpandFreeList();
        }

        //get free memory from head
        CMemoryPool<T>* pHead = m_pFreeList;
        m_pFreeList = m_pFreeList->m_pFreeList;
        return pHead;
    }

    void Free(void* p)
    {
        //push the free memory back to list
        CMemoryPool<T>* pHead = static_cast<CMemoryPool<T>*>(p);
        pHead->m_pFreeList = m_pFreeList;
        m_pFreeList = pHead;
    }

protected:
    //allocate memory and push to the list
    void ExpandFreeList(unsigned nItemCount = EXPANSION_SIZE)
    {
        unsigned int nSize = sizeof(T) > sizeof(CMemoryPool<T>*) ? sizeof(T) : sizeof(CMemoryPool<T>*);     //取大的

        //申請一段空間
        CMemoryPool<T>* pLastItem = static_cast<CMemoryPool<T>*>(static_cast<void*>(new char[nSize]));
        m_pFreeList = pLastItem;

        for (int i = 0; i<nItemCount - 1; ++i)
        {
            pLastItem->m_pFreeList = static_cast<CMemoryPool<T>*>(static_cast<void*>(new char[nSize]));
            pLastItem = pLastItem->m_pFreeList;
        }

        pLastItem->m_pFreeList = NULL;
    }
};

MTMemoryPool.h (加鎖的版本)

#pragma once
class CCriticalSection
{
public:
    CCriticalSection()
    {
        InitializeCriticalSection(&m_cs);
    }

    ~CCriticalSection()
    {
        DeleteCriticalSection(&m_cs);
    }

    void Lock()
    {
        EnterCriticalSection(&m_cs);
    }

    void Unlock()
    {
        LeaveCriticalSection(&m_cs);
    }

protected:
    CRITICAL_SECTION m_cs;
};

template<typename POOLTYPE, typename LOCKTYPE>
class CMTMemoryPool
{
public:
    void* Alloc(unsigned int size)
    {
        void* p = NULL;
        m_lock.Lock();
        p = m_pool.Alloc(size);
        m_lock.Unlock();

        return p;
    }

    void Free(void* p)
    {
        m_lock.Lock();
        m_pool.Free(p);
        m_lock.Unlock();
    }

private:
    POOLTYPE m_pool;
    LOCKTYPE m_lock;
};

read more :
深入探究C++的new/delete操作符:
https://kelvinh.github.io/blog/2014/04/19/research-on-operator-new-and-delete/

C++ 實現(xiàn)高性能內存池 :
https://blog.csdn.net/xjtuse2014/article/details/52302083

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铐望,隨后出現(xiàn)的幾起案子冈涧,更是在濱河造成了極大的恐慌,老刑警劉巖正蛙,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件督弓,死亡現(xiàn)場離奇詭異,居然都是意外死亡乒验,警方通過查閱死者的電腦和手機愚隧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锻全,“玉大人狂塘,你說我怎么就攤上這事■幔” “怎么了荞胡?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵蜈亩,是天一觀的道長斑芜。 經(jīng)常有香客問我,道長衰齐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任窖梁,我火速辦了婚禮赘风,結果婚禮上,老公的妹妹穿的比我還像新娘纵刘。我一直安慰自己邀窃,他們只是感情好,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布假哎。 她就那樣靜靜地躺著瞬捕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舵抹。 梳的紋絲不亂的頭發(fā)上肪虎,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音惧蛹,去河邊找鬼扇救。 笑死,一個胖子當著我的面吹牛香嗓,可吹牛的內容都是我干的迅腔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼靠娱,長吁一口氣:“原來是場噩夢啊……” “哼沧烈!你這毒婦竟也來了?” 一聲冷哼從身側響起像云,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锌雀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后迅诬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腋逆,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年侈贷,在試婚紗的時候發(fā)現(xiàn)自己被綠了闲礼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡铐维,死狀恐怖,靈堂內的尸體忽然破棺而出慎菲,到底是詐尸還是另有隱情嫁蛇,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布露该,位于F島的核電站睬棚,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜抑党,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一包警、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧底靠,春花似錦害晦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鳄逾,卻和暖如春稻轨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雕凹。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工殴俱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枚抵。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓线欲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親俄精。 傳聞我的和親對象是個殘疾皇子询筏,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355