欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++設(shè)計(jì)一個(gè)簡單內(nèi)存池的全過程

 更新時(shí)間:2021年09月20日 09:58:18   作者:午飯要陽光  
利用C/C++開發(fā)大型應(yīng)用程序中,內(nèi)存的管理與分配是一個(gè)需要認(rèn)真考慮的部分,下面這篇文章主要給大家介紹了關(guān)于C++設(shè)計(jì)一個(gè)簡單內(nèi)存池的全過程,需要的朋友可以參考下

什么是內(nèi)存池???

通常我們用new或malloc來分配內(nèi)存的話,由于申請(qǐng)的大小不確定,所以當(dāng)頻繁的使用時(shí)會(huì)造成內(nèi)存碎片和效率的降低。為了克服這種問題我們提出了內(nèi)存池的概念。內(nèi)存池是一種內(nèi)存分配方式。內(nèi)存池的優(yōu)點(diǎn)就是可以有效的減少內(nèi)存碎片化,分配內(nèi)存更快速,減少內(nèi)存泄漏等優(yōu)點(diǎn)。

內(nèi)存池是在真正使用內(nèi)存之前,先申請(qǐng)分配一個(gè)大的內(nèi)存塊留作備用。當(dāng)真正需要使用內(nèi)存的時(shí)候,就從內(nèi)存池中分配一塊內(nèi)存使用,當(dāng)使這塊用完了之后再還給內(nèi)存池。若是內(nèi)存塊不夠了就向內(nèi)存再申請(qǐng)一塊大的內(nèi)存塊。

可以看出這樣做有兩個(gè)好處:

  1、由于向內(nèi)存申請(qǐng)的內(nèi)存塊都是比較大的,所以能夠降低外碎片問題。

  2、一次性向內(nèi)存申請(qǐng)一塊大的內(nèi)存慢慢使用,避免了頻繁的向內(nèi)存請(qǐng)求內(nèi)存操作,提高內(nèi)存分配的效率。

內(nèi)存碎片化:

造成堆利用率很低的一個(gè)主要原因就是內(nèi)存碎片化。如果有未使用的存儲(chǔ)器,但是這塊存儲(chǔ)器不能用來滿足分配的請(qǐng)求,這時(shí)候就會(huì)產(chǎn)生內(nèi)存碎片化問題。內(nèi)存碎片化分為內(nèi)部碎片和外部碎片。

內(nèi)碎片:

內(nèi)部碎片是指一個(gè)已分配的塊比有效載荷大時(shí)發(fā)生的。(舉個(gè)栗子:假設(shè)以前分配了10個(gè)大小的字節(jié),現(xiàn)在只用了5個(gè)字節(jié),則剩下的5個(gè)字節(jié)就會(huì)內(nèi)碎片)。內(nèi)部碎片的大小就是已經(jīng)分配的塊的大小和他們的有效載荷之差的和。因此內(nèi)部碎片取決于以前請(qǐng)求內(nèi)存的模式和分配器實(shí)現(xiàn)的模式。

外碎片:   外部碎片就是當(dāng)空閑的存儲(chǔ)器的和計(jì)起來足夠滿足一個(gè)分配請(qǐng)求,但是沒有一個(gè)單獨(dú)的空閑塊足夠大可以處理這個(gè)請(qǐng)求。外部碎片取決于以前的請(qǐng)求內(nèi)存的模式和分配器的實(shí)現(xiàn)模式,還取決于于將來的內(nèi)存請(qǐng)求模式。所以外部碎片難以量化。

下面介紹一種簡單的內(nèi)存池,它是針對(duì)于某種對(duì)象實(shí)現(xiàn)的。 我們可以用一個(gè)鏈表實(shí)現(xiàn)這個(gè)內(nèi)存池,鏈表上的每個(gè)結(jié)點(diǎn)都是一個(gè)對(duì)象池,如果我們需要申請(qǐng)空間的話,直接去內(nèi)存池里面申請(qǐng)空間,當(dāng)用完之后再還給內(nèi)存池。

內(nèi)存池的設(shè)計(jì)主要包含三步:

1、初始化

在創(chuàng)建內(nèi)存池的時(shí)候?yàn)閮?nèi)存池分配了一塊很大的內(nèi)存,便于以后的使用。

2、分配內(nèi)存

當(dāng)需要內(nèi)存的時(shí)候就去內(nèi)存池里面分配內(nèi)存。

3、回收內(nèi)存

當(dāng)從內(nèi)存池里面分配來的內(nèi)存使用完畢之后,需要將這塊內(nèi)存還給內(nèi)存池。

設(shè)計(jì)上面這個(gè)內(nèi)存池最重要的問題就是如何重復(fù)利用釋放回來的內(nèi)存,讓利用率達(dá)到最高???

但是如果當(dāng)對(duì)象的大小小于對(duì)象指針的時(shí)候,也就是一個(gè)對(duì)象的空間存不下一個(gè)指針的大小,這時(shí)候就不可避免的產(chǎn)生內(nèi)碎片。   例如:為T類型對(duì)象開辟對(duì)象池,sizeof(T)<sizeof(T*),這時(shí)候我們就要為一個(gè)T類型對(duì)象申請(qǐng)sizeof(T*)大小的內(nèi)存。

代碼實(shí)現(xiàn):
#pragma once
#include<iostream>
using namespace std;
//用鏈表來實(shí)現(xiàn)內(nèi)存池,每一個(gè)結(jié)點(diǎn)都掛有一塊內(nèi)存
template<typename T>
class ObjectPool
{
       struct BlockNode         //每一個(gè)結(jié)點(diǎn)類型
       {
              void* _memory;        //指向一塊已經(jīng)分配的內(nèi)存
              BlockNode * _next;    //指向下一個(gè)結(jié)點(diǎn)
              size_t _objNum;       //記錄這塊內(nèi)存中對(duì)象的個(gè)數(shù)
              BlockNode(size_t objNum)
                     :_objNum(objNum)
                     , _next(NULL)
              {
                     _memory = malloc(_objNum*_itemSize);
              }
              ~BlockNode()
              {
                     free(_memory);
                     _memory = NULL;
                     _next = NULL;
                     _objNum = 0;
              }
       };
protected:
       size_t _countIn;      //當(dāng)前結(jié)點(diǎn)的在用的計(jì)數(shù)
       BlockNode* _frist;    //指向鏈表的頭
       BlockNode* _last;     //指向鏈表的尾
       size_t _maxNum;        //記錄內(nèi)存塊最大的容量
       static size_t _itemSize;   //單個(gè)對(duì)象的大小
       T* _lastDelete;        //指向最新釋放的那個(gè)對(duì)象的空間
public:
       ObjectPool(size_t initNum = 32, size_t maxNum = 100000)  //默認(rèn)最開始內(nèi)存塊有32個(gè)對(duì)象,一個(gè)內(nèi)存塊最大有maxNum個(gè)對(duì)象
              :_countIn(0)
              , _maxNum(maxNum)
              , _lastDelete(NULL)
       {
              _frist = _last =new BlockNode(initNum);   //先開辟一個(gè)結(jié)點(diǎn),這個(gè)結(jié)點(diǎn)里面的內(nèi)存塊能夠存放initNum個(gè)對(duì)象
       }
       ~ObjectPool()
       {
              Destory();
       }
       T* New()                   //分配內(nèi)存
       {
              if (_lastDelete)         //先到釋放已經(jīng)用完并且換回來的內(nèi)存中去找
              {
                     T* object = _lastDelete;
                     _lastDelete = *((T**)_lastDelete);  //將_lastDelete轉(zhuǎn)換成T**,*引用再取出來T*,也就是取出前T*類型大小的單元
                     return new(object) T();        //把這塊內(nèi)存用從定位new初始化一下
              }
              //判斷還有沒有已經(jīng)分配的內(nèi)存且還未使用,如果沒有內(nèi)存的話就要再分配內(nèi)存
              if (_countIn >= _last->_objNum)     //大于等于表示沒有了,這時(shí)候就要分配內(nèi)存了
              {
                     size_t size =2*_countIn;
                     if (size > _maxNum)            //塊的最大大小不能超過maxNum,如果沒超過就以二倍增長
                           size = _maxNum;
                     _last->_next = new BlockNode(size);
                     _last = _last->_next;
                     _countIn = 0;
              }
              //還有已經(jīng)分配好的未被使用的內(nèi)存
              T* object =(T*)((char*)_last->_memory + _countIn*_itemSize);
              _countIn++;
              return new(object) T();        //將這塊空間用重定位new初始化一下
       }
       void Destory()
       {
              BlockNode *cur = _frist;
              while (cur)
              {
                     BlockNode* del = cur;
                     cur = cur->_next;
                     delete del;            //會(huì)自動(dòng)調(diào)用~BlockNode()
              }
              _frist = _last = NULL;
       }
       void Delete(T* object)          //釋放內(nèi)存
       {
              if (object)
              {
                     object->~T();       
                     *((T**)object) = _lastDelete;      //將_lastDelete里面保存的地址存到tmp指向空間的前T*大小的空間里面
                     _lastDelete = object;
              }
       }
protected:
       static size_t GetItemSize()
       {
              if (sizeof(T)>sizeof(T*))
              {
                     return sizeof(T);
              }
              else
              {
                     return sizeof(T*);
              }
       }
};
template<typename T>
size_t ObjectPool<T>::_itemSize =ObjectPool<T>::GetItemSize();          //類外初始化靜態(tài)變量_itemSize

總結(jié)

到此這篇關(guān)于C++設(shè)計(jì)一個(gè)簡單內(nèi)存池的文章就介紹到這了,更多相關(guān)C++設(shè)計(jì)內(nèi)存池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論