STL空间配置器
Posted ZDF0414
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL空间配置器相关的知识,希望对你有一定的参考价值。
STL空间配置器分为第一级配置器与第二级配置器,主要用来对内存的申请与释放。
第一级配置器:调用的是malloc/free,并有 new-handle 机制
第二级配置器:由自由链表及内存池组成
自由链表:一个存储16个空闲块列表表头的数组free_list;
内存池 : 起始地址的指针start_free和一个指向结束地址的指针end_free之间的内存程序中的小对象的分配极易造成内存碎片(也叫外碎片),给操作系统的内存管理带来了很大压力,系统中碎片的增多不但会影响内存分配的速度,而且会极大地降低内存的利用率。
使用空间配置器,提高了空间的利用率和内存的分配速度,主要原因是:
(1)当内存申请超过128字节时,就会被视为大块内存,由第一级空间配置器处理;
(2)当内存申请小于等于128字节时,会对其使用二级空间配置
a) 先查找自由链表,如有空间,直接分配即可;
b)当a)不满足时,便会向内存池申请大块内存,一块返回申请,另外的挂到自由链表上,当反复申请该大小内存时,便极大的 提高了分配速度;
c)当内存池内存不足时,只返回满足要求的申请即可,适量分配空间;
d) 当内存池也满足不了要求时,便会向系统 malloc 一大段空间给内存池,再继续满足申请
e) 当系统内存紧张时,便会返回到看自由链表是否有闲置空间可释放至内存池;
f) 到山穷水尽的地步,便移交第一级空间配置器处理;
优点:(1)小对象的内存申请与释放快速(不用每次都要操作系统完成);
(2)解决了内存碎片的问题(外碎片);
(3)提高了空间利用率
缺点:引入了内碎片的问题
//第一级空间配置
template<int inst>
class __MallocAllocTemplate
public:
static void *Oom_Malloc(size_t size)
void(*my_malloc_handler)();
void *result;
while (1)
my_malloc_handler = __Malloc_Alloc_Oom_Handler;
if (my_malloc_handler == NULL)
throw bad_alloc();
(*my_malloc_handler)();
result = malloc(size);
if (result)
return(result);
static void * Allocate(size_t n)
void *result = malloc(n);
if (0 == result)
result = Oom_Malloc(n);
return result;
static void Deallocate(void *p, size_t /* n */)
free(p);
static void(*Set_Malloc_Handler(void(*f)()))()
void(*old)() = __Malloc_Alloc_Oom_Handler;
__Malloc_Alloc_Oom_Handler = f;
return(old);
private:
static void(*__Malloc_Alloc_Oom_Handler)();
;
template<int inst>
void(*__MallocAllocTemplate<inst>::__Malloc_Alloc_Oom_Handler)() = NULL;
//第二级空间配置
template <bool threads, int inst>
class __Default_Alloc_Template
public:
static void* Allocate(size_t n)
if (n > __MAX_BYTES)
return __MallocAllocTemplate<0>::Allocate(n);
size_t index = FREELIST_INDEX(n);
void* result = NULL;
if (free_list[index] == NULL)//如果自由串上没有内存,就去内存池上找空间
result = Refill(ROUND_UP(n));
else
result = free_list[index];
free_list[index] = free_list[index]->free_list_link;
return result;
static void* Refill(size_t n)
size_t nobjs = 20;
char * chunk = chunk_alloc(n, nobjs);//通过chunk_alloc函数获得内存
void* result = (void*)chunk;//把第一个满足的空间分配返回给申请者
if (nobjs == 1)
return result;
//把剩下的多分出的内存空间挂到自由链表上
else
size_t index = FREELIST_INDEX(n);
obj* cur = NULL;
obj* next = (obj*)((char*)chunk + n);
free_list[index] = next;
size_t i = 1;
for (; i < nobjs; i++)
cur = next;
next = (obj*)((char*)next + n);
cur->free_list_link = next;
cur->free_list_link = NULL;
return result;
static char* chunk_alloc(size_t n, size_t& nobjs)
size_t totalbytes = n*nobjs;
size_t poolbytes = _end_free - _start_free;//内存池现有的内存情况
char* result;//返回分配的内存
if (poolbytes >= totalbytes)
result = _start_free;
_start_free += totalbytes;//降低水位线,内存池内存减少
return result;
else if (poolbytes > n)//内存池满足不了一次分配20个该大小的内存,但至少满足一个(够需求)
nobjs = poolbytes / n;//当前内存池可满足多少个n
totalbytes = n*nobjs;
result = _start_free;
_start_free += totalbytes;
return result;
else
//内存池的内存不足
//重新为内存池申请大小,大小为bytes_to_get
size_t bytes_to_get = 2 * totalbytes + ROUND_UP(_heap_size >> 4);
//1、先把内存池中剩余的内存挂到自由链表的相应位置上
if (poolbytes > 0)
size_t index = FREELIST_INDEX(poolbytes);
((obj*)_start_free)->free_list_link = free_list[index];
free_list[index] = (obj*)_start_free;
_start_free = (char*)malloc(bytes_to_get);
if (_start_free == 0)
//申请内存失败
//解决方法:在自由链表上比它大的位置查找是否有空闲内存
for (size_t i = n; i <= __MAX_BYTES; i += __ALIGN)
size_t index = FREELIST_INDEX(n);
obj* p = free_list[index];
if (p != 0)
//找到满足要求的内存
free_list[index] = free_list[index]->free_list_link;
_start_free = (char*)p;
_end_free = _start_free + n;
return chunk_alloc(n, nobjs);
//自由链表上没有可提供的内存,就只能转第一种空间配置的方法了
_start_free = (char*)__MallocAllocTemplate<0>::Allocate(bytes_to_get);
_heap_size += bytes_to_get;
_end_free = _start_free + bytes_to_get;
return(chunk_alloc(n, nobjs));
static void Deallocate(void*p, size_t n)
if (n > __MAX_BYTES)
__MallocAllocTemplate<0>::Deallocate(p, n);
else
obj* tmp = (obj*)p;
size_t index = FREELIST_INDEX(n);
tmp->free_list_link = free_list[index];
free_list[index] = tmp;
protected:
static size_t FREELIST_INDEX(size_t n)
return (n + __ALIGN - 1) / __ALIGN - 1;
static size_t ROUND_UP(size_t bytes)//保证字节数与8字节对齐
return (((bytes)+__ALIGN - 1) & ~(__ALIGN - 1));
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 * free_list[__NFREELISTS];
//内存池
static char * _start_free;
static char * _end_free;
static size_t _heap_size;//总共为内存池分配的空间字节数
;
template <bool threads, int inst>
typename __Default_Alloc_Template<threads, inst>::obj * __Default_Alloc_Template<threads, inst>::free_list[__NFREELISTS] = NULL ;
template <bool threads, int inst>
char* __Default_Alloc_Template<threads, inst>::_start_free = NULL;
template <bool threads, int inst>
char* __Default_Alloc_Template<threads, inst>::_end_free = NULL;
template <bool threads, int inst>
size_t __Default_Alloc_Template<threads, inst>::_heap_size = 0;
以上是关于STL空间配置器的主要内容,如果未能解决你的问题,请参考以下文章