Memory Pool Implementation and Analysis

Memory Pool Implementation and Analysis

description

Program inevitable because of the need to dynamically allocate memory, and extensive use of heap memory. If you are using the default function of new / delete or malloc / free to allocate and free memory on the heap, not efficient, but also may produce large amounts of memory fragmentation, leading to increasingly fall after a long run performance. To improve performance, you usually need to consider using some of the data structures and algorithms to reduce the incidence of dynamically allocated memory pool which is the source of this idea.

In our server, you can see a large number of applications and situations frequently occur in ecstasy memory portion of the received data processing network in, so in this part of the process we need to consider the use of memory pool to optimize performance.

ALGORITHM

The method used was similar to the first in the allocator SGI STL memory allocator implementation. Design an array, is responsible for managing memory pages (MemPage). Each memory page can be assigned even fixed size block of memory in the range between 8Bytes 64MBytes.

MemPage memory block is created in the application period of continuous space size, while the other array of each block is located with a recording memory address allocated when allocation when free memory space, the purpose of releasing releasable by modifying the position of the array pointed to .

Structured as follows:
avatar

Implementation details

First, the structure size limit is defined as follows:

#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_ 的大小

The dispenser structure is then defined as follows:

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

Memory pages MemPage design:

Memory page is structured as follows:

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

Minimum memory page size is 1MByte limit, the size of each application are more than the size of the allocated time is calculated according to the size of the application binary digit blocks, then the memory page size, block size is determined according to the system application. If the size is less than the monolith 1MByte, the presence of a plurality of blocks in a page.

Additional pages construct an array, the array corresponding to a block address that each element page.

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

Distribution operations:

When needed is a space, computing the nearest power of two rounded up, the median is calculated, directly next to the index of the array MemPage bits, then there MemPage find an idle position and a dispensing space.

Such as the need 10Bytes, is closest 16Bytes, indexed _usedPage [4], and acquires the number of pages based on the last index distribution and the actual distribution:

//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);
}

The above method of calculating the index is because of the restrictions in accordance with the page size of 1MB, i.e., the memory address 20 are spaced above the minimum, it can be eliminated to obtain a unique index by the displacement operation, and also the release time of the memory address calculation redistribution by direct out of the memory block where the memory page.

The method wherein, after finding a suitable page, take the free blocks in the page as follows:

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

Release operation:

When release of the memory, the index can be calculated in the same current memory block is located by the index calculating method used above to find the corresponding page and release. When released only need to free memory pages indexed +1 and an array of free memory address of the block address can be re-recorded.

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

Guess you like

Origin www.cnblogs.com/zhqherm/p/11809321.html