STL实现简单的空间配置器
Posted 巴山雨夜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL实现简单的空间配置器相关的知识,希望对你有一定的参考价值。
1、模拟实现STL源码中实现的空间配置器
实现方式: STL源码中的空间配置器的实现分为一级与二级空间配置器;1.1 一级空间配置器
所谓的一级空间配置器:(实现特点) 【1】直接使用malloc函数申请内存 【2】自定义清除函数;(当malloc失败之后,调用清除函数来释放一部分的内存空间,以便malloc的成功) 【3】假设调用清除函数之后,还是malloc失败的话,就需要抛出异常 (bad_alloc) 代码实现://实现一级空间配置器
template<int inst>
class __Malloc_Alloc_Template
public:
static void* allocate(size_t n)
void * result = malloc(n);
//要是malloc失败
if(result == NULL)
//调用omm_malloc函数
result = omm_malloc(n);
return result;
//空间释放
static void deallocate(void * del)
//直接调用free
free(del);
//设置自定义的清理函数 函数返回的是原来的清理函数
//函数原型的意思就是
//定义一个函数 返回值是 静态的函数指针参数为空
//这个函数的参数为 函数指针参数 为 空 func
static void (*set_malloc_handler(void (* func)()))()
void (*old) = ___malloc_alloc_oom_handler;
___malloc_alloc_oom_handler = func;
return old;
private:
static void (*___malloc_alloc_oom_handler)();
//表示当前malloc失败内存不足,调用自定义的清理函数
static void * omm_malloc(size_t n)
void (*my_malloc_handler)();
void *result =NULL;
while(1)
my_malloc_handler = ___malloc_alloc_oom_handler;
//表示的当前的清理函数为空的话
if(my_malloc_handler == NULL)
//直接抛出异常
throw bad_alloc();
//调用清理函数
my_malloc_handler();
//调用完之后重新malloc来申请空间
result = malloc(n);
if(result)
return result;
;
template<int inst>
void (*__Malloc_Alloc_Template<inst>::___malloc_alloc_oom_handler)()=NULL;
1.2 二级空间配置器
实现方式: 在这里引入内存池与自由链表来实现二级空间配置二级空间配置器的优缺点:
【内存池】
我们都知道,编译器在用户态与内核态之间的转换是十分的耗时的。 所以,我们可以事先申请一大片的内存空间;将它保存起来,等到需要动态开辟空间的时候,直接到这块空间上切一块, 直到用完之后,重新申请;【自由链表】
何为自由链表? 就是使用链表将所需要大小的内存块链到一块。SGI二級空间配置器保存的自由链表的空间块大小都是8的倍数;并且会將任何小区域的内存块的大小調至8 的倍數(
各自管理大小分別為 8, 16, 24, 32, 40, 48, 56, 64, 72,80, 88, 96, 104, 112, 120, 128 bytes, 当需要的空间大小超过128byte时,直接调用一级空间配置器。
实现代码:
//实现二级空间配置器
template<bool threads,int inst>
class __Default_Alloc_Template
public:
static void * allocate(size_t n)
//要是当前要开辟的空间大于128的则直接使用 一级空间配置器来malloc开辟
if(n >(size_t) __MAX_BYTES)
return __Malloc_Alloc_Template<0>::allocate(n);
//小于128的直接到自由链表中获取
//index:得到大小为n的空间要在自由链表的下标为index处获得
size_t index = FREELIST_INDEX(n);
//result表示的就是自由链表的第一结点;
obj* result = free_list[index];
if(result== NULL)
//要是当前result 为NULL 表示的当前的自由链表中没有当前大小的内存块
//需要从内存池中进行切分
return refill(ROUND_UP(n));
//表示的当前的自由链表中有此大小的内存块;直接拿到;
//更新当前的自由链表
free_list[index] = result->free_list_link;
return result;
//refill函数表示的是要是当前的自由链表中没有此大小的内存块
//需要来从内存池中来切分
static void * refill(size_t n)
//表示现在需要到内存池中切分20个这样大小的内存块
size_t nobjs= 20;
//chunk_alloc为切分函数
char * chunk = chunk_alloc(n,nobjs);
//nobjs表示输出函数 返回的是实际切分到的内存块个数
if(nobjs == 1)
//要是只切分到一个内存块的话,直接返回就好
return (void *) chunk;
//其他就表示的是得到的内存块的个数大于1
//需要将剩余的内存块挂接到的自由链表中
size_t index = FREELIST_INDEX(n);
//cur表示的就去除第一个要返回的内存块,的第二个内存块
obj * cur = (obj*)chunk + n;
free_list[index] = cur;
for(size_t i = 2;i < nobjs;++i)
obj * next = (obj*)(chunk + i*n);
cur->free_list_link = next;
cur= next;
cur->free_list_link = NULL;
return (void *)chunk;
//chunk_alloc函数来从内存池中切分大小为size的内存块 需要的个数为nobjs
//nobjs传引用 ,返回的是实际切分的内存块个数
static char * chunk_alloc(size_t size,size_t & nobjs)
char * ret = NULL;
size_t total_bytes = size * nobjs;//表示总共需要切分的内存大小
size_t bytes_left = end_free - start_free;//表示的是当前的内存池的大小
if(bytes_left > total_bytes)
//表示的是当前的内存池足够切分当前需要的内存块
ret = start_free;
start_free += total_bytes;//更新内存池的大小
return ret;
else if(bytes_left >=size)
//表示的是当前的内存池内不足以开辟当前需要的内存块
//但足够开辟至少一个内存块
nobjs = bytes_left /size;//表示的当前切分到的内存块个数
ret =start_free ;
start_free += (nobjs*size);
return ret;
else
//表示的是当前的内存池一个内存块都不够切分
//则需要重新malloc来开辟空间
if(bytes_left != 0)//当前的内存池大小不为0 ,需要处理剩余的内存
//将当前内存池中的空间合理的分配得到自由链表中
int index = FREELIST_INDEX(bytes_left);
//头插到到自由链表中
((obj*)start_free)->free_list_link = free_list[index];
free_list[index] = (obj*)start_free;
//重新开辟新空间
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size>>4);//bytes_to_get表示新开辟空间的大小
start_free = (char*)malloc(bytes_to_get);
if(start_free == NULL)
//表示的是malloc失败,系统已经开不出空间
//现在只能从自由链表中来看看
for(size_t i = FREELIST_INDEX(size);i < (size_t)__NFREELISTS;++i )
if(free_list[i] != NULL)
start_free = (char*)free_list[i];
end_free = start_free + (i+1)*__ALIGN;
return chunk_alloc(size,nobjs);
end_free = 0 ;
start_free = (char*)__Malloc_Alloc_Template<0>::allocate(bytes_to_get);
heap_size = heap_size+ bytes_to_get;
end_free = start_free + bytes_to_get;
return chunk_alloc(size,nobjs);
static void deallocate(void * p,size_t n)
obj * del =(obj*) p;
//要是当前释放的空间大小大于128直接使用一级空间配置器释放
if( n >(size_t)__MAX_BYTES )
__Malloc_Alloc_Template<0>::deallocate(p);
return ;
//将释放的空间连到自由链表上
size_t index = FREELIST_INDEX(n);
del->free_list_link = free_list[index];
free_list[index] = del;
private:
//表示的小型的区域的上调边界
enum __ALIGN = 8;
//自由链表的链接的内存的最大值
enum __MAX_BYTES =128;
//表示的是自由链表的个数
enum __NFREELISTS = __MAX_BYTES / __ALIGN;
//ROUND_UP函数将bytes上调到 8 的倍数
static size_t ROUND_UP(size_t bytes)
//任何数+ 7 将这个数 与上 FFF0
return (bytes +__ALIGN-1)& ~(__ALIGN-1);
//根据要开辟的空间大小来得到 该大小在自由链表中的下标
static size_t FREELIST_INDEX(size_t bytes)
return (bytes + __ALIGN-1)/(__ALIGN-1);
private:
//链表的结点
union obj
union obj * free_list_link ;//自由链表
char client_data[1];
;
//自由链表数组 ,内部保存一个个的内存块链表
static obj * free_list[__NFREELISTS];
static char* start_free;//内存池的起点
static char* end_free;//内存池的结尾
static size_t heap_size ;//内存池的大小;
;
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>
typename __Default_Alloc_Template<threads,inst>::obj* __Default_Alloc_Template<threads,inst>::free_list[__Default_Alloc_Template<threads,inst>::__NFREELISTS] = 0;
template<bool threads,int inst>
size_t __Default_Alloc_Template<threads,inst>::heap_size = 0;
2、空间配置器的包装与运用方式
实现:
#ifdef __USE_MALLOC
typedef __Malloc_Alloc_Template<0> alloc;
#else
typedef __Default_Alloc_Template<false,0> alloc;
#endif //__USE_MALLOC
template<class T ,class Alloc =alloc>
class simple_alloc
public:
//n表示的是申请T类型的空间的个数
static T * allocate(size_t n)
return 0==n ? NULL : (T *)Alloc::allocate(n*sizeof(T));
//表示申请一个T类型的空间
static T * allocate(void)
return (T*)Alloc::allocate(sizeof(T));
static void deallocate(T * del)
Alloc::deallocate(del,sizeof(T));
static void deallocate(T * del,size_t n)
if( n!=0)
Alloc::deallocate(del,sizeof(T)*n);
;
#include<vector>
void Test()
int * array = simple_alloc<int,alloc>::allocate(2);
array[0]=0;
array[1]=1;
cout<<array[0]<<endl;
cout<<array[1]<<endl;
以上是关于STL实现简单的空间配置器的主要内容,如果未能解决你的问题,请参考以下文章