空间配置器
来源:互联网 发布:清华大学网络学堂登录 编辑:程序博客网 时间: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
- STL空间配置器
- STL空间配置器
- SGI_STL_空间配置器
- 15 空间配置器
- 2 空间配置器
- 空间配置器
- STL空间配置器
- 空间配置器实现
- 【STL】空间配置器
- 简单空间配置器
- STL空间配置器
- STL----空间配置器
- STL-空间配置器
- STL_7:空间配置器
- 空间配置器allocator
- STL空间配置器
- 空间配置器
- STL空间配置器
- 异常类型
- ZOJ 3956 Course Selection System (dp 01背包)
- clreol函数
- Ecshop模板开发(二十二):商品浏览记录显示
- sdut_java_下沉的船
- 空间配置器
- Java关于接口引用实现该接口类的对象
- Publishing Settings (keystore password) 保存密码
- 王道机试第三章总结
- jq 实现 验证码倒计时(前端部分)
- swustoj大整数加法(0434)
- 图论——BZOJ4239 巴士走读
- NOI 2010 能量采集
- 从零搭建Maven本地私服和简单使用