数据结构内存管理c++实现

内存管理边界标识首次拟合c++实现,持续更新中。。。

///
/// Copyright (c) 2014 xseekerj, All Rights Reserved.
///
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <mutex>

#define nullptr 0

inline int rrand(int min, int max)  
{
    return ( rand() % ((max) - (min)) + (min) );
}

/*
 * size in bytes constant: SZ Definition
 */
#ifndef _POL_SZ
#define _POL_SZ
static const uint64_t __B__ =  (1);
static const uint64_t __KB__ = (1024 * __B__) ;
static const uint64_t __MB__ = (1024 * __KB__);
static const uint64_t __GB__ = (1024 * __MB__);
static const uint64_t __TB__ = (1024 * __GB__);
static const uint64_t __PB__ = (1024 * __TB__);
static const uint64_t __EB__ = (1024 * __PB__);
#define __b__ __B__
#define __k__ __K__
#define __m__ __M__
#define __g__ __G__
#define __t__ __T__
#define __e__ __E__
#define __K__ __KB__
#define __M__ __MB__
#define __G__ __GB__
#define __T__ __TB__
#define __P__ __PB__
#define __E__ __EB__
#define SZ(n, u) ( (n) * __##u##__ )
static const uint8_t __MAX_UINT8 = SZ(256, B) - 1;
static const uint16_t __MAX_UINT16 = SZ(64, KB) - 1;
static const uint32_t __MAX_UINT32 = SZ(4, GB) - 1;
static const uint64_t __MAX_UINT64 = SZ(15, EB) + (SZ(1, EB) - 1);
#endif   /* _POL_SZ */
#define sz_align(d,a) (((d) + (a - 1)) & ~(a - 1))  

// #define EANBLE_MULTI_THREAD 1

class mempool 
{
struct memblock_head_t
{
    memblock_head_t* prev;
    memblock_head_t* next;
    size_t           size;
    bool             unused;
}; 

struct memblock_foot_t
{
    memblock_head_t* uplink;
}; 

static const size_t reserved_size = sizeof(memblock_head_t) + sizeof(memblock_foot_t);
static const size_t min_size = sizeof(void*) * 2;
static const size_t min_block_size = reserved_size + min_size;

#define FOOT_LOC(h) ((memblock_foot_t*)( (char*)h + h->size - sizeof(memblock_foot_t) ) )
#define HEAD_LOC(pu) ( (memblock_head_t*)( (char*)pu - sizeof(memblock_head_t) ) )
#define UPDATE_FOOT(h) ( FOOT_LOC(h)->uplink = h )

#define LEFT_FOOT_LOC(h) ( (memblock_foot_t*)( (char*)h - sizeof(memblock_foot_t) ) )
#define RIGHT_HEAD_LOC(h) ( (memblock_head_t*)( (char*)h + h->size ) )

#define REMAIN_SIZE(blk,n) (blk->size - reserved_size - (n) ) // calculate remain size after n bytes allocated.


public:
    mempool(size_t size = SZ(64, k))
    {
        init(size);
    }
    ~mempool(void)
    {
        free(memory_);
    }

    void init(size_t size)
    {
        size = sz_align(size, SZ(64, k));
        memory_ = malloc(size);

        memblock_head_t* header = (memblock_head_t*)(memory_);
        header->size = size;
        header->unused = true;
        header->prev = header;
        header->next = header;

        this->freelist_ = FOOT_LOC(header)->uplink = header;
        this->memory_size_ = size;
    }

    void* allocate(size_t size)
    {
#ifdef EANBLE_MULTI_THREAD
        std::unique_lock<std::mutex> guard(this->mtx_);
#endif

        size_t n = sz_align(size, min_size);

        memblock_head_t* blk = freelist_;
        for(; blk != nullptr && 
            blk->size - reserved_size < n && 
            blk->next != freelist_; blk = blk->next){;}

        if(blk == nullptr || blk->size - reserved_size < n) {
            return malloc(size);
        }
        else {
            blk->unused = false;
            char* p = (char*)blk + sizeof(memblock_head_t);

            if( REMAIN_SIZE(blk, n) < min_block_size ) /* can't construct the new memory block to respond any alloc request. */
            {
                // blk->size = 
                if(blk == freelist_) {
                    freelist_ = nullptr;
                }
                else {
                    freelist_->prev = blk->next; blk->next->prev = freelist_;
                }
            }
            else {
                /* remain block */
                memblock_head_t* reblock = (memblock_head_t*)(p + n + sizeof(memblock_foot_t));
                reblock->unused = true;
                reblock->size = (char*)blk + blk->size - (char*)reblock;
                UPDATE_FOOT(reblock);

                blk->size = (char*)reblock - (char*)blk;
                UPDATE_FOOT(blk);

                if(blk->next == blk)
                { // self
                    blk->next = reblock;
                    blk->prev = reblock;
                    reblock->prev = blk;
                    reblock->next = blk;
                }
                else { // insert
                    reblock->prev = blk;
                    reblock->next = blk->next;

                    blk->next->prev = reblock;
                    blk->next = reblock;
                    // ptr->prev = reblock;
                }

                freelist_ = reblock;
            }
            return p;
        }
    }

    void deallocte(void* pUserData)
    {
        if(!belong_to(pUserData))
        {
            free(pUserData);
            return;
        }

#ifdef EANBLE_MULTI_THREAD
        std::unique_lock<std::mutex> guard(this->mtx_);
#endif
        memblock_head_t* curh = HEAD_LOC(pUserData);
        memblock_foot_t* lf = LEFT_FOOT_LOC(curh);
        memblock_head_t* rh = RIGHT_HEAD_LOC(curh);
        bool vlf = is_valid_leftf(lf);
        bool vrh = is_valid_righth(rh);

#ifdef _DEBUG
        memset(pUserData, 0x0, curh->size - reserved_size);
#endif

        if( ( vlf && lf->uplink->unused ) && (!vrh || !rh->unused) )
        { // merge curret to left block
            lf->uplink->next = curh->next;
            if(curh->next != nullptr)
                curh->next->prev = lf->uplink;

            lf->uplink->size += curh->size;

            UPDATE_FOOT(lf->uplink);
            this->freelist_ = lf->uplink;
        }
        else if( (vrh && rh->unused) && (!vlf || !lf->uplink->unused ) )
        { // merge right to current block
            curh->unused = true;
            curh->next = rh->next;
            if(rh->next != nullptr)
                rh->next->prev = curh;
            curh->size += rh->size;

            UPDATE_FOOT(curh);
            this->freelist_ = curh;
        }
        else if( (vlf && lf->uplink->unused) && (vrh && rh->unused) )
        { // merge current and right to left block
            lf->uplink->next = rh->next;
            if(rh->next != nullptr)
                rh->next->prev = lf->uplink;

            lf->uplink->size += (curh->size + rh->size);

            UPDATE_FOOT(lf->uplink);
            this->freelist_ = lf->uplink;
        }
        else {
            // no need merge
            curh->unused = true;
            this->freelist_ = curh;
        }
    }

    bool belong_to(void* p)
    {
        return p >= this->memory_ && p < ( (char*)this->memory_ + this->memory_size_ );
    }

    bool is_valid_leftf(void* lf)
    {
        return ((char*)lf > ( (char*)this->memory_ + sizeof(memblock_head_t)) );
    }

    bool is_valid_righth(void* rh)
    {
        return (char*)rh < ((char*)this->memory_ + memory_size_ - sizeof(memblock_foot_t) );
    }

private:
    void*            memory_;
    size_t           memory_size_; // memory total size;
    memblock_head_t* freelist_;
#ifdef EANBLE_MULTI_THREAD
    std::mutex       mtx_;
#endif
};

int main(int argc, char** argv)
{
    /*apr_allocator_t* allocator;
    apr_allocator_create(&allocator);

    apr_memnode_t* node = apr_allocator_alloc(allocator, SZ(3, k));
    apr_allocator_free(allocator, node);
    node = apr_allocator_alloc(allocator, SZ(3, k));*/

    int times = 1000000;
    mempool pool;

    char* p1 = (char*)pool.allocate(25);
    strcpy(p1, "hello world");

    char* p2 = (char*)pool.allocate(25);
    char* p3 = (char*)pool.allocate(25);
    char* p4 = (char*)pool.allocate(25);

    pool.deallocte(p2);
    pool.deallocte(p4);
    pool.deallocte(p3);
    pool.deallocte(p1);
    double end[4];

    clock_t start = clock();
    for(int i = 0; i < times; ++i)
    {
        void* p = malloc(rrand(sizeof(int), 8192 * 2));
        if(p)
            free(p);
    }
    end[0] = (clock() - start) / (double)CLOCKS_PER_SEC;

    start = clock();
    for(int i = 0; i < times; ++i)
    {
        void* p = pool.allocate(rrand(sizeof(int), 8192 * 2));
        if(p)
            pool.deallocte(p);
    }
    end[1] = (clock() - start) / (double)CLOCKS_PER_SEC;

    start = clock();
    for(int i = 0; i < times; ++i)
    {
        void* p = malloc(sizeof(int));
        if(p)
            free(p);
    }
    end[2] = (clock() - start) / (double)CLOCKS_PER_SEC;

    /*start = clock();
    for(int i = 0; i < times; ++i)
    {
        apr_memnode_t* p = apr_allocator_alloc(allocator, rrand(sizeof(int), 8192 * 2));
        if(p)
            apr_allocator_free(allocator, p);
    }
    end[3] = (clock() - start) / (double)CLOCKS_PER_SEC;*/

    printf("malloc/free random size %d times, use %lf seconds\n", times, end[0]);
    printf("mempool allocate/deallocte random size %d times, use %lf seconds\n", times, end[1]);
    printf("malloc/free fixed size %d times, use %lf seconds\n", times, end[2]);
    //printf("apr alloc/free random size %d times, use %lf seconds\n", times, end[3]);

    /* result at win32 release:
    malloc/free random size 1000000 times, use 7.251000 seconds
    mempool allocate/deallocte random size 1000000 times, use 0.031000 seconds
    malloc/free fixed size 1000000 times, use 0.360000 seconds
    apr alloc/free random size 1000000 times, use 0.031000 seconds
    */
    /* result at linux release
    malloc/free random size 1000000 times, use 0.070000 seconds
    mempool allocate/deallocte random size 1000000 times, use 0.030000 seconds
    malloc/free fixed size 1000000 times, use 0.040000 seconds
    apr alloc/free random size 1000000 times, use 0.040000 seconds
    */
#ifdef _WIN32
    system("pause");
#endif
    return 0;
}


以下是结合固定大小内存快实现的内存池管理

// mempool2.h: a simple mempool implementation
#ifndef _MEMPOOL2_H_
#define _MEMPOOL2_H_

#ifndef _POLITE_SZ_ALIGN
#define _POLITE_SZ_ALIGN
#define sz_align(d,a) (((d) + ((a) - 1)) & ~((a) - 1))  
// #define sz_align(x,n) ( (x) + ( (n) - (x) % (n) ) - ( ( (x) % (n) == 0 ) * (n) ) )
#endif

/*
 * _POL_CONSTANTS_ Definitions
 */
#ifndef _POL_CONSTANTS
#define _POL_CONSTANTS
static const uint64_t __B__ =  (1);
static const uint64_t __KB__ = (1024 * __B__) ;
static const uint64_t __MB__ = (1024 * __KB__);
static const uint64_t __GB__ = (1024 * __MB__);
static const uint64_t __TB__ = (1024 * __GB__);
static const uint64_t __PB__ = (1024 * __TB__);
static const uint64_t __EB__ = (1024 * __PB__);
#endif  /* _POL_CONSTANTS */
#include <memory>
/*
 * TEMPLATE TYPE structs Definition
 */
#ifndef _POL_BOOL
#define _POL_BOOL
template<typename _Int>
struct Bool
{
    typedef _Int type;
    static const type True = ~0;
    static const type False = 0;
} ;
#endif /* _POL_BOOL */

/*
 * size in bytes constant: SZ Definition
 */
#ifndef _POL_SZ
#define _POL_SZ
#define __b__ __B__
#define __k__ __K__
#define __m__ __M__
#define __g__ __G__
#define __t__ __T__
#define __e__ __E__
#define __K__ __KB__
#define __M__ __MB__
#define __G__ __GB__
#define __T__ __TB__
#define __P__ __PB__
#define __E__ __EB__
#define SZ(n, u) ( (n) * __##u##__ )
static const uint8_t __MAX_UINT8 = SZ(256, B) - 1;
static const uint16_t __MAX_UINT16 = SZ(64, KB) - 1;
static const uint32_t __MAX_UINT32 = SZ(4, GB) - 1;
static const uint64_t __MAX_UINT64 = SZ(15, EB) + (SZ(1, EB) - 1);
#endif   /* _POL_SZ */

#include <assert.h>
#include <stdint.h>

namespace thelib {
namespace gc {

class object_pool2 
{
    typedef struct free_link_node
    { 
        free_link_node* next; 
    } *free_link;

    typedef struct chunk_link_node
    {
        chunk_link_node* next; /* at start of data */
        char            data[0];
    } *chunk_link;

    object_pool2(const object_pool2&);
    void operator= (const object_pool2&);

public:
    object_pool2(size_t elemsize, size_t elemcount) : _Myhead(nullptr), _Mychunk(nullptr), _Mycount(0), _MyElemSize(elemsize), _MyElemCount(elemcount)
    {
        this->_Enlarge();
    }

    ~object_pool2(void)
    {
        this->purge();
    }

    void cleanup(void)
    {
        if(this->_Mychunk = nullptr) {
            return;
        }

        free_link_node* prev = nullptr;
        chunk_link_node* chunk = this->_Mychunk;
        for (; chunk != nullptr; chunk = chunk->next) 
        {
            char* begin     = chunk->data; 
            char* rbegin    = begin + (_MyElemCount - 1) * _MyElemSize; 

            if(prev != nullptr)
                prev->next = reinterpret_cast<free_link>(begin);
            for (char* ptr = begin; ptr < rbegin; ptr += _MyElemSize )
            { 
                reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + _MyElemSize);
            } 

            prev = reinterpret_cast <free_link_node*>(rbegin); 
        } 

        this->_Myhead = reinterpret_cast<free_link_node*>(this->_Mychunk->data);
        this->_Mycount = 0;
    }

    void purge(void)
    {
        chunk_link_node* ptr = this->_Mychunk;
        while (ptr != nullptr) 
        {
            chunk_link_node* deleting = ptr;
            ptr = ptr->next;
            free(deleting);
        }
        _Myhead = nullptr;
        _Mychunk = nullptr;
        _Mycount = 0;
    }

    size_t count(void) const
    {
        return _Mycount;
    }

    // if the type is not pod, you may be use placement new to call the constructor,
    // for example: _Ty* obj = new(pool.get()) _Ty(arg1,arg2,...);
    void* get(void) 
    {
        if (nullptr == this->_Myhead) 
        { 
            this->_Enlarge(); 
        }
        free_link_node* ptr = this->_Myhead;
        this->_Myhead = ptr->next;
        ++_Mycount;
        return reinterpret_cast<void*>(ptr);
    }

    void release(void* _Ptr)
    {
        free_link_node* ptr = reinterpret_cast<free_link_node*>(_Ptr);
        ptr->next = this->_Myhead;
        this->_Myhead = ptr;
        --_Mycount;
    }

private:
    void _Enlarge(void)
    {
        // static_assert(_ElemCount > 0, "Invalid Element Count");
        chunk_link new_chunk  = (chunk_link)malloc(sizeof(chunk_link_node) + _MyElemCount * _MyElemSize); 
        if(new_chunk == nullptr)
            return;
#ifdef _DEBUG
        ::memset(new_chunk, 0x00, sizeof(chunk_link_node) + _MyElemCount * _MyElemSize);
#endif
        new_chunk->next = this->_Mychunk; 
        this->_Mychunk  = new_chunk; 

        char* begin     = this->_Mychunk->data; 
        char* rbegin    = begin + (_MyElemCount - 1) * _MyElemSize; 

        for (char* ptr = begin; ptr < rbegin; ptr += _MyElemSize )
        { 
            reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + _MyElemSize);
        } 

        reinterpret_cast <free_link_node*>(rbegin)->next = nullptr; 
        this->_Myhead = reinterpret_cast<free_link_node*>(begin); 
    }

private:
    free_link        _Myhead; // link to free head
    chunk_link       _Mychunk; // chunk link
    size_t           _Mycount; // allocated count 
    const size_t     _MyElemSize; // elem size
    const size_t     _MyElemCount; // elem count
}; /* equalize size block */

#ifndef _INLINE_ASM_BSR
#define _INLINE_ASM_BSR
#ifdef _WIN32
#pragma intrinsic(_BitScanReverse)
#define BSR(_Index, _Mask) _BitScanReverse((unsigned long*)&_Index, _Mask);
#else
#define BSR(_Index,_Mask) __asm__ __volatile__("bsrl %1, %%eax\n\tmovl %%eax, %0":"=r"(_Index):"r"(_Mask):"eax")
#endif
#endif

class mempool2
{
    static const size_t MAX_INDEX = 11;
    static const size_t BOUNDARY_INDEX = 5 + sizeof(void*) / 8; // 5 at x86_32, 6 at x86_64
    static const size_t BOUNDARY_SIZE = (1 << BOUNDARY_INDEX); // 32bytes at x86_32, 64bytes at x86_64
public:
    mempool2(void)
    {
        init();
    }
    ~mempool2(void)
    {
        for(size_t index = 0; index <= MAX_INDEX; ++index)
        {
            delete blocks[index];
        }
    }
    void* allocate(size_t in_size)
    {
        uint32_t size = sz_align(in_size + sizeof(uint32_t), BOUNDARY_SIZE);
        uint32_t index = 0;
        BSR(index, size >> BOUNDARY_INDEX);
        index += (bool)((size-1) & size); // adjust index
        void* raw = nullptr;
        if(index <= MAX_INDEX) 
        {
            raw = this->blocks[index]->get();
        }
        else {
            raw = malloc(size);
        }

        if(raw != nullptr) {
            *reinterpret_cast<uint32_t*>(raw) = size;
            return (char*)raw + sizeof(uint32_t);
        }

        return nullptr;
    }
    void deallocate(void* p)
    {
        char* raw = (char*)p - sizeof(uint32_t);
        uint32_t size = *reinterpret_cast<uint32_t*>( raw );
        uint32_t index = 0;
        BSR(index, size >> BOUNDARY_INDEX);
        index += (bool)((size-1) & size); // adjust index
        if(index <= MAX_INDEX) {
            this->blocks[index]->release(raw);
            return;
        }
        free(raw);
    }

private:
    void init(void)
    {
        for(size_t index = 0; index <= MAX_INDEX; ++index)
        {
            size_t elem_size = BOUNDARY_SIZE << index;
            blocks[index] = new object_pool2(elem_size, SZ(512,k) / elem_size);
        }
    }

    object_pool2* blocks[MAX_INDEX + 1];
}; // namespace: thelib::gc::mempool2

}; // namespace: thelib::gc
}; // namespace: thelib


#endif
/*
* Copyright (c) 2014 by X.D. Guo  ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
**/







  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值