メモリプールの実装と分析

メモリプールの実装と分析

説明

なぜなら、動的にメモリを割り当てる必要があり、ヒープメモリの広範な使用の必然的なプログラム。あなたは、ヒープ上に割り当て、メモリを解放し自由に新しい/削除したり、malloc関数のデフォルト機能を/使用して効率的ではありませんが、また、ますます長期のパフォーマンスの後に下落につながる、メモリの断片化を大量に生産することがあります。している場合 パフォーマンスを向上させるには、通常、このアイデアの源である動的に割り当てられたメモリプールの発生率を低下させるために、データ構造とアルゴリズムの一部を使用することを検討する必要があります。

当社のサーバーでは、アプリケーションや状況の多くは頻繁に私たちは、最適化のパフォーマンスへのメモリ・プールの使用を考慮する必要があり、プロセスのこの部分では、ネットワークを処理し、受信データのエクスタシーメモリ部で発生見ることができます。

アルゴリズム

使用される方法は、アロケータSGI STLメモリアロケータの実装の最初のと同様でした。配列を設計し、メモリページ(MemPage)を管理する責任があります。各メモリページは8バイト64Mバイトの範囲でメモリのも固定サイズのブロックを割り当てることができます。

各ブロックの他のアレイが場合割り当てとき空きメモリ空間に割り当てられた記録メモリアドレスに配置されている間MemPageメモリブロックは、連続した空間サイズの適用期間内に作成され、アレイの位置を変更することにより解放解放の目的は指さ。

次のように構造化:
アバター

実装の詳細

次のように第一、構造のサイズ制限が定義されています。

#define _MIN_BLOCK_SIZE_        (8)             //单内存块最小限制为8 Byte
#define _MAX_BLOCK_SIZE_        (1 << 26 )      //单内存块最大限制为64 MByte
#define _PAGE_MIN_SIZE_         (1024 * 1024)   //单页大小最小限制为1 MByte
#define _PAGE_INDEX_COUNT_      (27)            //对应上面的26位大小限制,所以数组定为27
#define _PAGE_COUNT_            (4096)          //限制分配不超过4096页
#define _PAGE_MIN_BITS_         (20)            //单页大小限制的位数,对应 _PAGE_MIN_SIZE_ 的大小

次のようにディスペンサの構造は、次に定義されます。

class CAllocator
{
public:
    CAllocator();
    virtual ~CAllocator();
    
    virtual void *malloc (size_t nbytes);
    virtual void free (void *ptr);
    virtual void *realloc( void * pTemp , size_t nSize );
private:

    size_t _lastIndex[_PAGE_INDEX_COUNT_];                      //记录每一位最后用来分配的索引
    size_t _pageCount[_PAGE_INDEX_COUNT_];                      //记录每一位的已分配页数量

    CMemPage* _bitPages[_PAGE_INDEX_COUNT_][_PAGE_COUNT_];      //管理每一位的页mempage
    CMemPage* _pages[_PAGE_COUNT_];                             //管理所有页mempage
};

メモリページMemPageデザイン:

次のようにメモリページが構成されています。

class CMemPage
{    
private:
    size_t _pageSize;       //页大小
    size_t _blockSize;      //块大小
    size_t _blockCount;     //块数量
    size_t _freeIndex;      //空闲索引
    size_t* _freeBlocks;    //块地址数组
};

最小のメモリページサイズは、1Mバイトの限界で、各アプリケーションのサイズが割り当てられた時間のサイズは、アプリケーションバイナリ桁ブロックのサイズは、メモリ・ページ・サイズに従って計算さ以上であり、ブロック・サイズは、システムの用途に応じて決定されます。サイズはモノリス1Mバイト、ページ内の複数のブロックの存在よりも小さい場合。

追加のページは、配列、各要素のページそのブロックアドレスに対応する配列を構築します。

static MemPage* mallocPage(size_t blockSize)
{
    size_t size = getBit(blockSize);
    size_t pageSize = _PAGE_MIN_SIZE_ + sizeof(MemPage);
    if(size > _PAGE_MIN_SIZE_)
    {
        pageSize = size + sizeof(MemPage);
    }
    void* buf = ::malloc(pageSize);
    if(NULL == buf) return NULL;

    MemPage page(size, pageSize, buf);
    memcpy(buf, &page, sizeof(page));
    return (MemPage*)buf;
}

MemPage(size_t blockSize, size_t pageSize, void* const start)
            :_pageSize(0),_blockSize(0),_freeIndex(0)
{
    memset(this, 0, sizeof(MemPage));

    _pageSize = pageSize;

    _blockSize = blockSize;
    if(blockSize < _MIN_BLOCK_SIZE_)
    {
        _blockSize = _MIN_BLOCK_SIZE_;
    }

    _blockCount = (_pageSize - sizeof(MemPage)) / blockSize;
    _freeBlocks = (size_t*)::malloc(_blockCount * sizeof(size_t));

    for(size_t i = 0; i < _blockCount; ++i)
    {
        _freeNodes[i] = (size_t)((char*)start + sizeof(MemPage) + i * _blockSize);
    }
    _freeIndex = _blockCount;
}

物流業務:

切り上げ最も近い2のコンピューティングパワー、スペースで必要なときに、中央値は、直接次の配列MemPageビットのインデックスに、アイドル位置と分配空間が見つけMemPage、計算されます。

そのような必要10Bytesとして、最も近い16バイト、インデックス付き_usedPage [4]は、最後の屈折率分布と実際の分布に基づいて、ページ数を取得します。

//malloc函数
//计算出 bit = getBit(10) = 4,以下直接使用4来说明

lastIdx = _lastIndex[4];
pageCount = _pageCount[4];

//在lastIdx~pageCount之间找空余页
for (int i = lastIdx; i < pageCount; ++i)
{
    if (_bitPages[4][i]->isFree())
    {
        //分配内存
        _lastIndex[4] = i;
        return _bitPages[4][i]->malloc(bytes);
    }
}

//如果在lastIdx~pageCount之间都无法找到空余页,寻找0~lastIdx
for (int i = 0; i < lastIdx; ++i)
{
    if (_bitPages[4][i]->isFree())
    {
        //分配内存
        _lastIndex[4] = i;
        return _bitPages[4][i]->malloc(bytes);
    }
}

//如果依然无法分配,新建页
MemPage *memPage = MemPage::mallocPage(bytes);
if( NULL != memPage )
{
    _bitPages[4][ _pageCount[4]++ ] = memPage;
    size_t index = (size_t)memPage >> _PAGE_MIN_BITS_;
    _pages[ index ] = memPage;
    return memPage->malloc(bytes);
}

指数を計算する上記方法はすなわち、メモリアドレス20が最小の上方に間隔を置いて配置され、変位操作によって一意のインデックスを取得するために除去することができ、なぜなら1メガバイトのページサイズに応じて制限であり、また、直接によるメモリアドレス計算の再分配の放出時間メモリページのメモリブロックのうち。

次のように方法であって、適したページを発見した後、ページ内の空きブロックを取ります:

void* mallocNode(size_t size)
{
    return (void*)_freeBlocks[--_freeIndex];
}

リリース操作:

メモリの解放は、インデックスが同じ現在のメモリブロックに計算することができる場合、対応するページと解放を見つけるために上記使用率算出方法により配置されています。リリースされた場合のみ空きメモリページに必要な+1をインデックス化し、ブロックアドレスの空きメモリアドレスの配列は、再記録することができます。

void CAllocator::free(void *ptr)
{
    if(!ptr)
    {
        return;
    }

    size_t index = (size_t)ptr >> (_PAGE_MIN_BITS_);
    MemPage* memPage = _memPages[index];
    if(!memPage || memPage > ptr)
    {
        --index;
    }
    memPage = _memPages[index];
    
    memPage->freeNode(ptr);
}

bool freeNode(void* node)
{
    _freeBlocks[_freeIndex++] = (size_t)node;
    return true;
}

おすすめ

転載: www.cnblogs.com/zhqherm/p/11809321.html