您的位置:首页 > 其它

STL源码——特殊的空间配置器

2016-12-14 11:57 288 查看
源代码展示:https://github.com/uagvdu/Memory/blob/STL-MyAllocate/MyAllocator.h

STL标准的空间配置器 就是将new和delete进行了简单的封装,这里不是重点,就懒得说了。而且这个标准的空间配置器也没被进行使用。

SGI特殊的空间配置器:



一级配置器的实现:

就是正常的malloc和free,但在此的基础上添加了一个事件处理:即针对于malloc返回值为NULL的情况,系统内存开辟失败的一些处理。

处理失败的内存分配要求的其他方法:编写自定义恢复例程来处理此类失败,然后通过调用 _set_new_handler 运行时函数来注册您的函数。/官方解释 /

设置一个函数句柄: 系统在内存配置需求无法被满足的情况下,调用一个你所指定的函数,

因为函数的每次调用都会消耗内存的空间,当函数返回又会释放内存。不断的进行调用,说不定就会有合适的内存。(废话多就知道是本人解释)

:malloc开辟空间失败的情况:
typedef void(*ALLOC_HANDLER)();//定义一个函数句柄,
static ALLOC_HANDLER __mallocAllocOomHandler;

static void* OOM_Malloc(size_t n)
{
void* ret;
while (1)
{
if (__mallocAllocOomHandler == NULL)//如果这个函数都不存在,代表系统一点空间都不会剩余,那么也就只能抛异常
{
throw bad_alloc();
}
else
{
//期望释放内存
(*__mallocAllocOomHandler)();//调用函数消耗内存,返回函数释放内存,一直循环下去,说不定就会有合适的空间被释放从而开辟出来需要的空间
ret = malloc(n);
if (ret)
{
return ret;
}
}
}
}




二级配置器:

//先列出来一些成员变量
public:
enum{ __ALIGN = 8 };// 基准值
enum{ __MAX = 128 };    //区块最大字节数;
enum{ __BLOCKNUM = __MAX / __ALIGN}; //区块个数

protected:
union Obj            //共用体,省空间
{
union Obj* _freelistlink;
char _clientDate[1];
};

static Obj* _freelist[__BLOCKNUM];    //存放自由链表的指针数组

// Chunk allocation state.
static char* _start_free;   //大块的首地址
static char *_end_free;    //大块的尾地址
static size_t _heap_siz;   //附加量,开辟所需大小的内存池的时候附加的内存空间




最重要的还是二级配置器:而且这也算是 SGI 版本的内存池 :

/二级配置器简单来说就一两句话:一个指针数组存放自由链表头指针,自由链表指向对应的内存块,每一个数组成员含义是代表内存区块的大小,自由链表指向对应的内存块 /

思路: 1.如果所需区块<字节数>过大,超过128 bytes,则调用一级空间配置器进行处理.

2.当所需区块<字节数>小于128bytes时,则需要求得其所对应的区块位置。< free_list成员为8的倍数,数组每个成员代表区块的大小  >

3.找到对应的位置然后查找该处是否有剩余的区块,若有,则直接从free_list对应的位置中拨出区块,因为是链表,所以记得要指向下一个位置。若没有,则需要调用refill(),准备为free_list重新填充区块,新的空间将取自内存池。

4.内存池的空间:refill()重新填充给free_list时,要看内存池的大小 ,若内存池
小于一个区块:连一个所需要的区块都没有,就只能进行重新开辟
大于一个区块:返回chunk,内存池chunk之后的内存池经过分割对应的区块大小之后连在free_list中
等于一个区块:直接返回chunk,也不用在free_list中添加区块,因为其初始值就是NULL;
5.有申请就会有释放:当释放的区块<字节数> 大于128bytes时,就调用一级空间配置器进行处理,否则就直接连在free_list对应的位置中。<头插>


上面的一二级配置器只是实现了空间的开辟和释放,SGI还为它包装了一个类 ,使配置器接口能够符合STL规格:

template<class T,class _alloc>
class SimpleAlloc  //仅仅只是空间配置器的接口
{
public:
static T* allocate() //单个对象
{
T* dst = _alloc::Allocate(sizeof(T));
return dst;
}

static T* allocate(size_t n )//多个对象或者数组,
{
T* dst = _alloc::Allocate(n*sizeof(T));
return 0==n? 0:dst;
}
static void  deallocate(T* ptr,size_t n)
{
if (n != 0)
_alloc::Deallocate(ptr, n*sizeof(T));
}
static  void deallocate(T* ptr)
{
_alloc::Deallocate(ptr, n*sizeof(T));
}
};


其内部函数知识单纯的转调用,调用传递给配置器,这个接口使配置器的配置单位从字节数转为个别元素的大小,或者元素的个数。SGI STL容器全部都是用这个simple_alloc接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: