<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          內存池設計與實現(xiàn)

          共 3687字,需瀏覽 8分鐘

           ·

          2021-10-13 21:45

          內存池設計與實現(xiàn)


          一、前言

          作為C++程序員,想必對于內存操作這一塊是比較熟悉和操作比較頻繁的;

          比如申請一個對象,使用new,申請一塊內存使用malloc等等;

          但是,往往會有一些困擾煩惱著大家,主要體現(xiàn)在兩部分:

          • 申請內存后忘記釋放,造成內存泄漏
          • 內存不能循環(huán)使用,造成大量內存碎片

          這兩個原因會影響我們程序長期平穩(wěn)的運行,也有可能會導致程序的崩潰;


          二、內存池

          內存池是池化技術中的一種形式。通常我們在編寫程序的時候回使用 new delete 這些關鍵字來向操作系統(tǒng)申請內存,而這樣造成的后果就是每次申請內存和釋放內存的時候,都需要和操作系統(tǒng)的系統(tǒng)調用打交道,從堆中分配所需的內存。如果這樣的操作太過頻繁,就會找成大量的內存碎片進而降低內存的分配性能,甚至出現(xiàn)內存分配失敗的情況。

          而內存池就是為了解決這個問題而產生的一種技術。從內存分配的概念上看,內存申請無非就是向內存分配方索要一個指針,當向操作系統(tǒng)申請內存時,操作系統(tǒng)需要進行復雜的內存管理調度之后,才能正確的分配出一個相應的指針。而這個分配的過程中,我們還面臨著分配失敗的風險。

          所以,每一次進行內存分配,就會消耗一次分配內存的時間,設這個時間為 T,那么進行 n 次分配總共消耗的時間就是 nT;如果我們一開始就確定好我們可能需要多少內存,那么在最初的時候就分配好這樣的一塊內存區(qū)域,當我們需要內存的時候,直接從這塊已經分配好的內存中使用即可,那么總共需要的分配時間僅僅只有 T。當 n 越大時,節(jié)約的時間就越多。

          ---引用來源互聯(lián)網


          三、內存池設計

          內存池設計實現(xiàn)中主要分為以下幾部分:

          • 重載new
          • 創(chuàng)建內存節(jié)點
          • 創(chuàng)建內存池
          • 管理內存池

          下面,比較詳細的來說說設計細節(jié):

          重載new就不說了,直接從內存節(jié)點開始;

          內存池節(jié)點

          內存池節(jié)點需要包含以下幾點元素:

          1. 所屬池子(pMem),因為后續(xù)在內存池管理中可以直接調用申請內存和釋放內存

          2. 下一個節(jié)點(pNext),這里主要是使用鏈表的思路,將所有的內存塊關聯(lián)起來;

          3. 節(jié)點是否被使用(bUsed),這里保證每次使用前,該節(jié)點是沒有被使用的;

          4. 是否屬于內存池(bBelong),主要是一般內存池維護的空間都不是特別大,但是用戶申請了特別大的內存時,就走正常的申請流程,釋放時也就正常釋放;

          內存池設計

          內存池設計就是上面的圖片類似,主要包含以下幾點元素:

          1. 內存首地址(_pBuffer),也就是第一塊內存,這樣以后方面尋找后面的內存塊;
          2. 內存塊頭(_pHeader),也就是上面說的內存池節(jié)點;
          3. 內存塊大?。?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">_nSize),也就是每個節(jié)點多大;
          4. 節(jié)點數(shù)(_nBlock),及時有多少個節(jié)點;

          這里面需要的注意的是,申請內存塊的時候,需要加上節(jié)點頭,但是申請完后返回給客戶使用的需要去掉頭;但是釋放的時候,需要前移到頭,不然就會出現(xiàn)異常;

          釋放內存:

          釋放內存的時候,將使用過的內存置為false,然后指向頭部,將頭部作為下一個節(jié)點,這樣的話,節(jié)點每次回收就可以相應的被找到;

          內存池管理

          內存池創(chuàng)建后,會根據(jù)節(jié)點大小和個數(shù)創(chuàng)建相應的內存池;

          內存池管理主要就是根據(jù)不同的需求創(chuàng)建不同的內存池,以達到管理的目的;

          這里主要有一個概念:數(shù)組映射

          數(shù)組映射就是不同的范圍內,選擇不同的內存池;

          添一段代碼:

          ?void?InitArray(int?nBegin,int?nEnd,?MemoryPool*pMemPool)
          ?
          {
          ??for?(int?i?=?nBegin;?i?<=?nEnd;?i++)
          ??{
          ???_Alloc[i]?=?pMemPool;
          ??}
          ?}

          根據(jù)范圍進行綁定;


          四、內存池實現(xiàn)

          ManagerPool.hpp

          #ifndef?_MEMORYPOOL_HPP_
          #define?_MEMORYPOOL_HPP_

          #include?
          #include?

          ////一個內存塊的最大內存大小,可以擴展
          #define?MAX_MEMORY_SIZE?256

          class?MemoryPool;

          //內存塊
          struct?MemoryBlock
          {

          ?MemoryBlock*?pNext;//下一塊內存塊
          ?bool?bUsed;//是否使用
          ?bool?bBelong;//是否屬于內存池
          ?MemoryPool*?pMem;//屬于哪個池子
          };

          class?MemoryPool
          {

          public:
          ?MemoryPool(size_t?nSize=128,size_t?nBlock=10)
          ?{
          ??//相當于申請10塊內存,每塊內存是1024
          ??_nSize?=?nSize;
          ??_nBlock?=?nBlock;
          ??_pHeader?=?NULL;
          ??_pBuffer?=?NULL;
          ?}
          ?virtual?~MemoryPool()
          ?{
          ??if?(_pBuffer?!=?NULL)
          ??{
          ???free(_pBuffer);
          ??}
          ?}
          ?//申請內存
          ?void*?AllocMemory(size_t?nSize)
          ?
          {
          ??std::lock_guard<std::mutex>?lock(_mutex);
          ??//如果首地址為空,說明沒有申請空間
          ??if?(_pBuffer?==?NULL)
          ??{
          ???InitMemory();
          ??}
          ??MemoryBlock*?pRes?=?NULL;
          ??//如果內存池不夠用時,需要重新申請內存
          ??if?(_pHeader?==?NULL)
          ??{
          ???pRes?=?(MemoryBlock*)malloc(nSize+sizeof(MemoryBlock));
          ???pRes->bBelong?=?false;
          ???pRes->bUsed?=?false;
          ???pRes->pNext?=?NULL;
          ???pRes->pMem?=?NULL;
          ??}
          ??else
          ??{
          ???pRes?=?_pHeader;
          ???_pHeader?=?_pHeader->pNext;
          ???pRes->bUsed?=?true;
          ??}
          ??//返回只返回頭后面的信息
          ??return?((char*)pRes?+?sizeof(MemoryBlock));
          ?}

          ?//釋放內存
          ?void?FreeMemory(void*?p)
          ?
          {
          ??std::lock_guard<std::mutex>?lock(_mutex);
          ??//和申請內存剛好相反,這里需要包含頭,然后全部釋放
          ??MemoryBlock*?pBlock?=?((MemoryBlock*)p?-?sizeof(MemoryBlock));
          ??if?(pBlock->bBelong)
          ??{
          ???pBlock->bUsed?=?false;
          ???//循環(huán)鏈起來
          ???pBlock->pNext?=?_pHeader;
          ???pBlock?=?_pHeader;
          ??}
          ??else
          ??{
          ???//不屬于內存池直接釋放就可以
          ???free(pBlock);
          ??}
          ?}
          ?//初始化內存塊
          ?void?InitMemory()
          ?
          {
          ??if?(_pBuffer)
          ???return;
          ??//計算每塊的大小
          ??size_t?PoolSize?=?_nSize?+?sizeof(MemoryBlock);
          ??//計算需要申請多少內存
          ??size_t?BuffSize?=?PoolSize?*?_nBlock;
          ??_pBuffer?=?(char*)malloc(BuffSize);
          ??//初始化頭
          ??_pHeader?=?(MemoryBlock*)_pBuffer;
          ??_pHeader->bUsed?=?false;
          ??_pHeader->bBelong?=?true;
          ??_pHeader->pMem?=?this;
          ??//初始化_nBlock塊,并且用鏈表的形式連接
          ??//保存頭指針
          ??MemoryBlock*?tmp1?=?_pHeader;
          ??for?(size_t?i?=?1;?i???{
          ???MemoryBlock*?tmp2?=?(MemoryBlock*)(_pBuffer?+?i*PoolSize);
          ???tmp2->bUsed?=?false;
          ???tmp2->pNext?=?NULL;
          ???tmp2->bBelong?=?true;
          ???_pHeader->pMem?=?this;
          ???tmp1->pNext?=?tmp2;
          ???tmp1?=?tmp2;
          ??}
          ?}
          public:
          ?//內存首地址(第一塊內存的地址)
          ?char*?_pBuffer;
          ?//內存塊頭
          ?MemoryBlock*?_pHeader;
          ?//內存塊大小
          ?size_t?_nSize;
          ?//多少塊
          ?size_t?_nBlock;

          ?std::mutex?_mutex;
          };

          //可以使用模板傳遞參數(shù)
          template<size_t?nSize,size_t?nBlock>
          class?MemoryPoolor:public?MemoryPool
          {
          public:
          ?MemoryPoolor()
          ?{
          ??_nSize?=?nSize;
          ??_nBlock?=?nBlock;
          ?}

          };

          //需要重新對內存池就行管理
          class?ManagerPool
          {

          public:
          ?static?ManagerPool&?Instance()
          ?
          {
          ??static?ManagerPool?memPool;
          ??return?memPool;
          ?}

          ?void*?AllocMemory(size_t?nSize)
          ?
          {
          ??if?(nSize???{
          ???return?_Alloc[nSize]->AllocMemory(nSize);
          ??}
          ??else
          ??{
          ???MemoryBlock*?pRes?=?(MemoryBlock*)malloc(nSize?+?sizeof(MemoryBlock));
          ???pRes->bBelong?=?false;
          ???pRes->bUsed?=?true;
          ???pRes->pMem?=?NULL;
          ???pRes->pNext?=?NULL;
          ???return?((char*)pRes?+?sizeof(MemoryBlock));
          ??}
          ?}

          ?//釋放內存
          ?void?FreeMemory(void*?p)
          ?
          {
          ??MemoryBlock*?pBlock?=?(MemoryBlock*)((char*)p?-?sizeof(MemoryBlock));
          ??//釋放內存池
          ??if?(pBlock->bBelong)
          ??{
          ???pBlock->pMem->FreeMemory(p);
          ??}
          ??else
          ??{
          ???free(pBlock);
          ??}
          ?}

          private:
          ?ManagerPool()
          ?{
          ??InitArray(0,128,?&_memory128);
          ??InitArray(129,?256,?&_memory256);
          ?}

          ?~ManagerPool()
          ?{
          ?}

          ?void?InitArray(int?nBegin,int?nEnd,?MemoryPool*pMemPool)
          ?
          {
          ??for?(int?i?=?nBegin;?i?<=?nEnd;?i++)
          ??{
          ???_Alloc[i]?=?pMemPool;
          ??}
          ?}
          ?//可以根據(jù)不同內存塊進行分配
          ?MemoryPoolor<128,?1000>?_memory128;
          ?MemoryPoolor<256,?1000>?_memory256;
          ?//映射數(shù)組
          ?MemoryPool*?_Alloc[MAX_MEMORY_SIZE?+?1];
          };
          #endif

          OperatorMem.hpp

          #ifndef?_OPERATEMEM_HPP_
          #define?_OPERATEMEM_HPP_

          #include?
          #include?
          #include?"MemoryPool.hpp"


          void*?operator?new(size_t?nSize)
          {
          ?return?ManagerPool::Instance().AllocMemory(nSize);
          }

          void?operator?delete(void*?p)
          {
          ?return?ManagerPool::Instance().FreeMemory(p);
          }

          void*?operator?new[](size_t?nSize)
          {
          ?return?ManagerPool::Instance().AllocMemory(nSize);
          }

          void?operator?delete[](void*?p)
          {
          ?return?ManagerPool::Instance().FreeMemory(p);
          }

          #endif

          mian.cpp

          #include?"OperateMem.hpp"

          using?namespace?std;

          int?main()
          {
          ?char*?p?=?new?char[128];
          ?delete[]?p;
          ?return?0;
          }
          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  俺去啦新网 | 成人久久| 777性爱| 精品成AV人片在线观看 | 人人操人人干人人摸 |