空间配置器

来源:互联网 发布:清华大学网络学堂登录 编辑:程序博客网 时间:2024/05/17 04:12

空间配置器:为了解决因频繁小块开辟时,产生的内存碎片问题。

如果开辟的内存大于128个字节时,就调用一级空间配置器,小于128个字节时,就调用二级空间配置器。

一级空间配器:封装了malloc()和free()。


注意:如果客户端设置的内存不足处理函数,没有设置好,会存在死循环的危险。

//一级空间配置器template <int inst>class __Malloc_Alloc_Template {private:static void *Oom_Malloc(size_t); //内存不足处理函数static MALLOCALLOC _Malloc_Alloc_Oom_Handler; //函数指针,内存不足的时候的处理机制public:static void* Allocate(size_t n) //n>128,就malloc直接开辟{void *result = malloc(n);if (0 == result)   //开辟失败result = Oom_Malloc(n);//调用内存不足处理函数return result;}static void Deallocate(void *p)  //释放内存{free(p);}static void (* Set_Malloc_Handler(MALLOCALLOC f) //让用户来设置内存不足时的处理机制{MALLOCALLOC old = _Malloc_Alloc_Oom_Handler;_Malloc_Alloc_Oom_Handler = f;return old;}};template <int inst>       void (*__Malloc_Alloc_Template<inst>::_Malloc_Alloc_Oom_Handler)()=0 ;//不设置内存不足的处理机制template <int inst>void* __Malloc_Alloc_Template<inst>::Oom_Malloc(size_t n){MALLOCALLOC My_Malloc_Handler; //定义函数指针void* result;while(1){My_Malloc_Handlerr=_Malloc_Alloc_Oom_Handler;if(My_Malloc_Handlerr==0) //不设置处理机制,直接抛出异常{throw bad_alloc();}(*My_Malloc_Handlerr)();  //调用内存不足处理机制的函数,申请释放其他地方的内存 result=malloc(n);if(result){return result;break;}}}
二级空间配置器:用到了自由链表和内存池。假设要分配8个字节大小的空间,那么他就会去内存池中分配多个8个字节大小的内存块(20*n),将多余的挂在自由链表上,下一

次再需要8个字节时就去自由链表上取就可以了,如果回收这8个字节的话,直接将它挂

在自由链表上就可以了。




//二级空间配置器template <bool threads, int inst>class __Default_Alloc_Template {private:enum {__ALIGN = 8}; //基准    enum {__MAX_BYTES = 128};  //最大的字节个数    enum {__NFREELISTS = __MAX_BYTES/__ALIGN}; //自由链表的长度union obj   //自由链表的节点类型{        union obj * free_list_link;        char client_data[1];    /* The client sees this.        */    };static size_t ROUND_UP(size_t bytes) //把bytes取向上取成8的整数倍{        return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));    }static  size_t FREELIST_INDEX(size_t bytes)     //用来计算bytes大小的空闲区在链表的那个位置上挂着{        return (((bytes) + __ALIGN-1)/__ALIGN - 1);}static obj * volatile free_list[__NFREELISTS]; //定义一个自由链表static char *start_free; //内存池的头指针    static char *end_free;   //内存池的尾指针    static size_t heap_size; //记录内存池已经向系统申请了多大的内存  public:  static void * Allocate(size_t n) //n<128,分配空间  {obj * volatile * my_free_list;  //防止编译器优化,防止使另一个线程可以修改void* result;if (n > (size_t) __MAX_BYTES)     //n>128,直接调用一级空间配置器{return Malloc_Alloc::Allocate(n);}//在自由链表中找my_free_list = free_list + FREELIST_INDEX(n); //指向在自由链表的那个位置上result = *my_free_list; //result指向这个节点下面挂的空间if (result == 0) //这个节点下没有内存{void *r = refill(ROUND_UP(n)); //去内存池申请return r;}//挂着空闲内存,直接返回*my_free_list = result -> free_list_link; //把第二块空间地址挂到自由链表节点下面return result;  }  static void deallocate(void *p, size_t n)  {obj *q = (obj *)p;obj * volatile * my_free_list;if (n > (size_t) __MAX_BYTES) //n>128{__Malloc_Alloc_Template<0>::Deallocate(q);return;}//头插到自由链表中my_free_list = free_list + FREELIST_INDEX(n);q -> free_list_link = *my_free_list;*my_free_list = q;  }private:  static void* refill(size_t n)//去内存池申请  {    int nobjs = 20; //向内存池一次性申请20个char * chunk = chunk_alloc(n, nobjs); obj * volatile * my_free_list;if (1 == nobjs) return chunk;obj* result = (obj *)chunk;    //将申请的第一个对象返回 my_free_list = free_list + FREELIST_INDEX(n);//将剩余的挂到自由链表上*my_free_list = (obj *)(chunk + n); obj* cur=*my_free_list;for (int i = 2;i<nobjs; i++) {obj* next= (obj*)(chunk + n*i);              cur->_freeListLink = next;              cur = next; } cur->_freeListLink = 0;      return result;  }  char* 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 New = 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(New);        if (0 == start_free) //没有内存,在自由链表中找一个比n的内存{            obj * volatile * my_free_list, *p;            for (int 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_Template<0>::Allocate(New);         }        heap_size += New;        end_free = start_free + New;        return chunk_alloc(size, nobjs); //在调用一次来分配内存    } };template <bool threads, int inst>char *__Default_Alloc_Template<threads,inst>::start_free=0; template <bool threads, int inst>char *__Default_Alloc_Template<threads,inst>::end_free=0;   template <bool threads, int inst>size_t __Default_Alloc_Template<threads,inst>::heap_size=0; template <bool threads, int inst>class _DefaultAllocTemplate<threads, inst>::obj * volatile_DefaultAllocTemplate<threads, inst>::free_list[__NFREELISTS]={0};



0 0