String系列——内存池技术

前言:阅读STL源码中内存池的实现,感触颇深,但又不知如何描述,STL源码剖析中已经描述的非常清楚了。所以这里我把其源码整理了一下,去除了多线程,方便阅读其实现原理。

头文件

内存池头文件

class MemoryPool {
private:
    static size_t ROUND_UP(size_t bytes) {
        return (((bytes) + 7) & ~(7));
    }

    union obj {
        union obj * free_list_link;
        char client_data[1];  
    };
private:
    static obj * volatile free_list[16]; 

    static  size_t FREELIST_INDEX(size_t bytes) {
        return (((bytes) + 7)/7);
    }

    static void *refill(size_t n);
    static char *chunk_alloc(size_t size, int &nobjs);

    // 分配状态
    static char *start_free;
    static char *end_free;
    static size_t heap_size;

public:
    //n必须大于0
    static void * allocate(size_t n)
    {
        obj * volatile * my_free_list;
        obj *  result;

        if (n > (size_t) 128) {
            //只处理小于128的情况
            return(::allocate(n));
        }
        my_free_list = free_list + FREELIST_INDEX(n);

        result = *my_free_list;
        if (result == 0) {
            void *r = refill(ROUND_UP(n));
            return r;
        }
        *my_free_list = result -> free_list_link;
        return (result);
    };

    /* p 不能为 0 */
    static void deallocate(void *p, size_t n)
    {
        obj *q = (obj *)p;
        obj * volatile * my_free_list;

        if (n > (size_t) 128) {
            ::deallocate(p, n);
            return;
        }
        my_free_list = free_list + FREELIST_INDEX(n);

        q -> free_list_link = *my_free_list;
        *my_free_list = q;

    }

    static void * reallocate(void *p, size_t old_sz, size_t new_sz);
} ;

其中在分配空间的时候用到了全局的分配函数,::deallocate(p, n);::allocate(n) 这在http://blog.csdn.net/z702143700/article/details/47166493这一节中给出。

实现

整个内存池的实现代码其实并不长,但是,不仔细研究是很难理解其中的奥秘,亲身体会,需要备注没有多少,研究源码是最好的解释。

char* MemoryPool::chunk_alloc(size_t size, int& nobjs)
{
    char * result;
    size_t total_bytes = size * nobjs;
    size_t bytes_left = end_free - start_free;

    if (bytes_left >= total_bytes) {
        result = start_free;
        start_free += total_bytes;
        return(result);
    } else if (bytes_left >= size) {
        nobjs = bytes_left/size;
        total_bytes = size * nobjs;
        result = start_free;
        start_free += total_bytes;
        return(result);
    } else {
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        if (bytes_left > 0) {
            obj * volatile * my_free_list =
                free_list + FREELIST_INDEX(bytes_left);

            ((obj *)start_free) -> free_list_link = *my_free_list;
            *my_free_list = (obj *)start_free;
        }
        start_free = (char *)malloc(bytes_to_get);
        if (0 == start_free) {
            int i;
            obj * volatile * my_free_list, *p;
            for (i = size; i <= 128; i += 8) {
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if (0 != p) {
                    *my_free_list = p -> free_list_link;
                    start_free = (char *)p;
                    end_free = start_free + i;
                    return(chunk_alloc(size, nobjs));
                }
            }
            end_free = 0;   
            start_free = (char *)malloc_alloc::allocate(bytes_to_get);

        }
        heap_size += bytes_to_get;
        end_free = start_free + bytes_to_get;
        return(chunk_alloc(size, nobjs));
    }
}

void* MemoryPool::refill(size_t n)
{
    int nobjs = 20;
    char * chunk = chunk_alloc(n, nobjs);
    obj * volatile * my_free_list;
    obj * result;
    obj * current_obj, * next_obj;
    int i;

    if (1 == nobjs) return(chunk);
    my_free_list = free_list + FREELIST_INDEX(n);

    result = (obj *)chunk;
    *my_free_list = next_obj = (obj *)(chunk + n);
    for (i = 1; ; i++) {
        current_obj = next_obj;
        next_obj = (obj *)((char *)next_obj + n);
        if (nobjs - 1 == i) {
            current_obj -> free_list_link = 0;
            break;
        } else {
            current_obj -> free_list_link = next_obj;
        }
    }
    return(result);
}


void* MemoryPool::reallocate(void *p,size_t old_sz,size_t new_sz)
{
    void * result;
    size_t copy_sz;

    if (old_sz > 128 && new_sz > 128) {
        return(realloc(p, new_sz));
    }
    if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
    result = allocate(new_sz);
    copy_sz = new_sz > old_sz? old_sz : new_sz;
    memcpy(result, p, copy_sz);
    deallocate(p, old_sz);
    return(result);
}

char *MemoryPool::start_free = 0;

char *MemoryPool::end_free = 0;

size_t MemoryPool::heap_size = 0;

MemoryPool::obj * volatile free_list[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

总结:在写内存池实现技术的时候,我参考很多了博主写的玩具内存吹实现,但是跟STL这个小型高效的内存池比起来还是相差很远很远的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值