STL空间配置器
来源:互联网 发布:网络信贷 编辑:程序博客网 时间:2024/06/06 09:17
为什么要有空间配置器?
1.内存碎片问题(外碎片)
由于频繁分配、释放小块内存容易在堆中造成外碎片(极端情况下就是堆中空闲的内存总量满足一个请求,但是这些空闲的块都不连续,导致任何一个单独的空闲的块都无法满足这个请求)。
2.频繁的分配小块内存,效率比较低。
开辟空间的时候,分配器去找一块空闲块给用户。找空闲块也是需要时间的,尤其是在外碎片比较多的情况下。 如果分配器其找不到,就要考虑处理假碎片现象(释放的小块空间没有合并),这时候就要将这些已经释放的的空闲块进行合并,这也是需要时间的。 malloc在开辟空间的时候,这些空间会带有一些附加的信息,这样的话也就造成了空间的利用率有所降低,尤其是在频繁申请小块内存的时候。
STL中的空间配置器分为两种:
一级空间配置器
二级空间配置器
在STL中默认如果要分配的内存大于128个字节的话就是大块内存,调用一级空间配置器直接向系统申请。
如果小于等于128个字节的话则认为是小内存,则就去内存池中申请。一级空间配置器很简单,直接封装了malloc和free处理,增加_malloc_alloc_oom_handle处理机制。二级空间配置器才是STL的精华,二级空间配置器主要由内存池和自由链表构成。
框架设计
流程及代码实现
“内存不足处理机制”是客户端的责任,设置”内存不足处理介质”也是客户端的责任。
//一级空间配置器template <int inst>class __MallocAllocTemplate{public: //static void(*__malloc_alloc_oom_handler)(); static HANDLE_FUNC __malloc_alloc_oom_handler; //HANDLE_FUNC 代表一个函数指针 static void* OOM_Malloc(size_t n) { while (1) { if (__malloc_alloc_oom_handler == 0) throw bad_alloc(); __malloc_alloc_oom_handler(); // 释放内存;如果设置了句柄,那么就会一直循环,直到申请到了,才会退出 void* ret = malloc(n); if (ret) return ret; } } static void* Allocate(size_t n) { void* ret = malloc(n); if (ret == NULL) //一级空间配置器没有申请到内存 { ret = OOM_Malloc(n); } return ret; } static void Deallocate(void* p, size_t n) { free(p); } static HANDLE_FUNC SetMallocHandler(HANDLE_FUNC f) { HANDLE_FUNC old = f; __malloc_alloc_oom_handler = f; return old; }};
//二级空间配置器template <bool threads, int inst>class __DefaultAlloceTemplate{public: static size_t FREELIST_INDEX(size_t bytes) { return ((bytes + __ALIGN - 1) / __ALIGN - 1); //找到链接的index } static size_t ROUND_UP(size_t bytes) { return ((bytes)+__ALIGN - 1)&(~(__ALIGN - 1));//变成8的倍数 } //在内存池中申请对象 static char* Chunk(size_t n, size_t &nobjs) { size_t needBytes = n * nobjs; //需要的大小(即20块内存) size_t leftBytes = _endfree - _startfree; //内存池中剩余的大小 //内存池中的内存足够申请n*nobjs大小的内存 if (needBytes <= leftBytes) //内存池中剩余的内存足够申请20块 { char* ret = _startfree; _startfree += needBytes; return ret; } //虽然不够申请needBytes,但是足够申请n大小的内存 else if (leftBytes > n) { nobjs = leftBytes / n; //计算内存池中剩余的内存足够申请多少块 needBytes = n*nobjs; char* ret = _startfree; _startfree += needBytes; return ret; } //剩余的内存连1个都申请不到 else { if (leftBytes > 0) //虽然不够申请一个,但是内存池中还有内存 { size_t index = FREELIST_INDEX(leftBytes); //将剩下的内存挂入自由链表 ((Obj*)_startfree)->free_list_link = _freeList[index]; (_freeList[index])->free_list_link = (Obj*)_startfree; } size_t byteToGets = needBytes * 2 + ROUND_UP(_heapsize >> 4); //malloc内存 _startfree = (char*)malloc(byteToGets); if (_startfree == NULL) //malloc失败了 { size_t index = FREELIST_INDEX(n); //去index后面的自由链表中找比它大的内存块,找到则放入内存池 for (size_t i = index; i < __NFREELISTS; ++i) { if (_freeList[i]) { _startfree = (char*)_freeList[i]; _freeList[i] = ((Obj*)_startfree)->free_list_link; _endfree = _startfree + (i + 1)*__ALIGN; return Chunk(n, nobjs); } } _endfree = 0; //自由链表中也没有更大的内存块了,调用一级空间配置器 _startfree = (char*)__MallocAllocTemplate<0>::Allocate(byteToGets); } _heapsize = _heapsize + byteToGets; _endfree = _startfree + _heapsize; return Chunk(n, nobjs); } } //填充自由链表 static char* Refill(size_t n) { size_t nobjs = 20; //一次申请二十个对象 char* ret = Chunk(n, nobjs); if (nobjs == 1) //nobjs=1说明只从内存池中拿到了一块内存,直接返回 { return ret; } else { size_t index = FREELIST_INDEX(n); _freeList[index] = (Obj*)(ret + n); //把剩下的内存块挂入自由链表 Obj* cur = _freeList[index]; for (size_t i = 1; i < nobjs; ++i) { Obj* next = (Obj*)((char*)cur + n); cur->free_list_link = next; cur = next; } cur->free_list_link = NULL; return ret; } } static void* Allocate(size_t n) { if (n > __MAX_BYTES) { return __MallocAllocTemplate<0>::Allocate(n); //如果申请的内存块大于128,则直接调用一级空间配置器的Allocate } size_t index = FREELIST_INDEX(n); //计算出index if (_freeList[index]) //index下面挂的有所需内存块 { Obj* ret = _freeList[index]; _freeList[index] = ret->free_list_link; return ret; } else return Refill(ROUND_UP(n)); //index下面没有所需内存块,则开始填充自由链表 } static void Deallocate(void* ptr, size_t n) { if (n > __MAX_BYTES) { __MallocAllocTemplate<0>::Deallocate(n); } size_t index = FREELIST_INDEX(n); //将还回来的内存挂入自由链表 Obj* obj = (Obj*)ptr; obj->_freeListLink = _freeList[index]; _freeList[index] = obj; }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 Obj*_freeList[__NFREELISTS]; static char*_startfree; static char*_endfree; static size_t _heapsize;};template <bool threads, int inst>char* __DefaultAlloceTemplate<threads, inst>::_startfree = 0;template <bool threads, int inst>char* __DefaultAlloceTemplate<threads, inst>::_endfree = 0;template <bool threads, int inst>size_t __DefaultAlloceTemplate<threads, inst>::_heapsize = 0;template <bool threads, int inst>typename __DefaultAlloceTemplate<threads, inst>::Obj*__DefaultAlloceTemplate<threads, inst>::_freeList[__NFREELISTS] = { 0 };
阅读全文
1 0
- 【STL】STL空间配置器
- STL空间配置器
- STL空间配置器
- STL空间配置器
- 【STL】空间配置器
- STL空间配置器
- STL----空间配置器
- STL-空间配置器
- STL空间配置器
- STL空间配置器
- STL空间配置器
- STL空间配置器
- STL-空间配置器
- STL空间配置器
- STL空间配置器
- 【STL】空间配置器
- STL空间配置器
- STL空间配置器
- Prim算法
- 卸载和安装LINUX上的JDK
- python第七周学习内容及测验作业
- 多线程的this.getName()与Thread.currentThread().getName为何有时不一样
- POJ 2184 Cow Exhibition(01背包)
- STL空间配置器
- 大数据学习笔记:Linux基础复习
- jquery layui
- Ubuntu16.04 安装流程 -3 编程-计算机视觉(201705)
- shell编程入门
- 优秀开源项目之四:CrashRptProbe,查询程序奔溃的利器
- HDU 1205(鸽巢原理)
- 可爱的中国
- 突然代码片不能创建了,只能这么写了.......