STL空间配置器

当用户申请的内存大于128时调用一级空间配置器。
小于或者等于128调用二级空间配置器。
一级空间配置器是malloc的封装,如果不能成功申请到空间,用户通过调用set_malloc_handler函数可以自己设定处理函数。
二级空间配置器类似哈希桶,将128的区块分为16个分别为8,16,24。。。128大小的区块,用free_list来保存.
这里写图片描述
用户每次申请小于128的内存,会提升的8的整数倍,释放后会加入到对应的区块中,下一次申请时在free_list中查找对应的区块,如果没有,再到内存池中获取。很大的提升了效率并且易于管理。

#include <iostream>
using namespace std;

//当用户申请内存大于128时使用一级空间配置器
template <int inst>
class malloc_Alloc_template {   
public:
    static void *allocate(size_t n)
    {
        void *result = malloc(n);
        if (n == 0)
            result = oom_malloc(n); //不满足要求进行处理
        return result;
    }
    static void dellocate(void *p, size_t)
    {
        free(p);
    }

    static void *reallocate(void *p, size_t old_size, size_t new_size)
    {
        void *result = realloc(p, new_size);
        if (0 == result)
            result = oom_realloc(p, new_size); 
        return result;
    }


    static void(*set_malloc_handler(void(*f)()))()//用户可以自己设定
                                                 //没有内存时重新分配的函数
    {
        void(*old)() = alloc_oom_handler;
        alloc_oom_handler = f;
        return old;
    }

private:
    static  void(* alloc_oom_handler)();
private:
    static void *oom_malloc(size_t n)
    {
        void *result;
        void(*f)(); 

        for (;;)
        {
            f = alloc_oom_handler;
            if (NULL == f)
            {
                cerr << "out of merroy" << endl;
                exit(1);
            }
            (*f)();
            result = malloc(n);
            if (result)
                return result;
        }
    }

    static void oom_realloc(void *p, size_t new_size)
    {
        void *result;
        void(*f)();

        for (;;)
        {
            f = alloc_oom_handler;
            if (NULL == f)
            {
                cerr << "out of merroy" << endl;
                exit(1);
            }
            *f();
            result = rellocc(p, old_size);
            if (result)
                return result;
        }
    }
};

template <int inst>
void(*malloc_Alloc_template<inst>::alloc_oom_handler)() = NULL; //静态成员初始化

typedef malloc_Alloc_template<0> malloc_Alloc;

//二级空间配置器

enum { ALIGN = 8 }; //小区块上界
enum { MAX_BYTES = 128 };  //区块上限
enum { FREELIST = MAX_BYTES / ALIGN }; //小区块个数

template <int inst>
class default_Alloc_template {
public:
    static void *allocate(size_t n);
    static void *reallocate(void *p, size_t old_size, size_t new_size);
    static void deallocate(void *p, size_t n);
private:
    //用于提升申请内存大小到小区块上界的倍数
    static size_t ROUND_UP(size_t bytes)
    {
        return ((bytes + ALIGN - 1) & ~(ALIGN - 1));
    }
    //下标
    static size_t FREELIST_INDEX(size_t bytes)
    {
        return ((bytes + ALIGN - 1) / ALIGN - 1);
    }

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

private:
    union obj{
        union obj* free_list_link;
        char client_data[1];
    };
private:
    static obj*  volatile free_list[FREELIST];
    static char* start_free; //内存池起始位置
    static char* end_free;  //内存池结束位置  
    static size_t heap_size;
};

template <int inst>
char *default_Alloc_template<inst>::start_free = 0;

template <int inst>
char *default_Alloc_template<inst>::end_free = 0;

template <int inst>
size_t default_Alloc_template<inst>::heap_size = 0;

template <int inst>
typename default_Alloc_template<inst>::obj* volatile
default_Alloc_template<inst>::free_list[FREELIST] = {0};

template <int inst>
void* default_Alloc_template<inst>::allocate(size_t n)
{
    obj* volatile *my_free_list;
    obj* result;
    // 大于128调用一级空间配置器
    if (n > (size_t)MAX_BYTES)
    {
        return (malloc_Alloc::allocate(n));
    }
    //判断应该使用my_free_list应该使用16个中的哪一个
    my_free_list = free_list + FREELIST_INDEX(n);
    result = *my_free_list;

    //没有找到,说明没有所需要的free_list
    if (0 == result)
    {
        void *r = refill(ROUND_UP(n));
        return r;
    }
    //有所需要的free_list,free_list指向下一个 
    *my_free_list = result->free_list_link;
    return result;
}

template <int inst>
void default_Alloc_template<inst>::deallocate(void *p, size_t n)
{
    obj *q = (obj *)p;
    obj * volatile *my_free_list;
    //大于128调用1级空间配置器的函数
    if (n > (size_t)FREELIST)
    {
        malloc_Alloc::dellocate(p, n);
        return;
    }
    my_free_list = free_list + FREELIST_INDEX(n);
    q->free_list_link = *my_free_list;
    *my_free_list = q;
}

//freelist没有可用的区块时,调用refill填充新空间
template <int inst>
void* default_Alloc_template<inst>::refill(size_t n)
{
    //默认取得20个区块
    int nobjs = 20;
    //从内存池取得区块给free_list使用
    char *chunk = chunk_alloc(n, nobjs);
    obj* volatile *my_free_list;
    obj* result;
    obj* cur_obj;
    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);
    //将剩余的区块交给free_list,各节点连接起来
    for (i = 1;; ++i)
    {
        cur_obj = next_obj;
        next_obj = (obj*)((char*)next_obj + n);
        if (nobjs - 1 == i)
        {
            cur_obj->free_list_link = 0;
            break;
        }
        else
        {
            cur_obj->free_list_link = next_obj;
        }
    }
    return result;
}
//从内存池取得空间交给free_list使用
template <int inst>
char *default_Alloc_template<inst>::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 = nobjs*size;
        result = start_free;
        start_free += total_bytes;
        return result;
    }
    //剩余内存无法提供1个大小的区块
    else
    {
        size_t bytes_toget = 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;
        }
        //配置heap空间,用来补充内存池
        start_free = (char*)malloc(bytes_toget);
        if (0 == start_free)
        {
            //heap空间不足,malloc失败
            int i;
            obj* volatile *my_free_list;
            obj* p;
            //从更大的区块尝试获取
            for (i = size; i <= MAX_BYTES; i += ALIGN)
            {
                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_toget);
        }
        heap_size += bytes_toget;
        end_free = start_free + bytes_toget;
        return (chunk_alloc(size, nobjs));
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏尔肖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值