标签:
SGISTL默认使用二级空间配置器,当需要配置的区块大于128 bytes时SGI STL调用一级空间配置器,一级空间配置器的allocate函数直接使用malloc分配内存,deallocate函数直接使用free释放内存。当需要配置的区块小于128 bytes时SGI STL调用二级空间配置器。
相比于一级空间配置器简单粗暴的内存使用方法,二级空间配置器对内存的使用显得精细很多。
二级空间配置器的具体用法请看书,我就不抄书了,只对二级空间配置器中容易糊涂的地方写一下我的理解。
内存池和free_list到底什么关系?
二级空间配置器维护了一个内存池,有一个名为free_list的数组负责管理内存池。free_list的每个元素构成一个链表,同一个链表的每个元素指向的内存大小相同,free_list的所有链表节点指向的内存大小 <= 内存池。
之所以使用数组而不是链表,我猜测有两个原因:1. 二级空间配置器把内存池分为固定的16个大小等级,即free_list的长度(16)是固定的;2.既然free_list的长度固定那么采用数组无疑是时间效率更高的方法(O(1)),如果采用链表,free_list的查询效率为O(n)。
一下是我理解的二级空间配置器执行过程,时间关系,不画程序流程图了。
1. 二级空间配置器在索要内存时调用allocate函数,如果索要的内存大于128字节,调用一级空间配置器,否则allocate查free_list数组,从free_list中某个元素指向的链表中取出一块内存后返回。
2. 当free_list没有合适的内存区块时调用refill函数。
3. refill调用_S_chunk_alloc,_S_chunk_alloc分配一段内存给内存池,把内存池残余的空间编入free_list。
4. _S_chunk_alloc 调用完毕,回到refill,refill查free_list数组,从free_list中某个元素指向的链表中取出一块内存后返回给allocate,allocate再返回给客户端。
_S_chunk_alloc函数的源码:
template <bool __threads, int __inst>
char*
__default_alloc_template<__threads,__inst>::_S_chunk_alloc(size_t __size,
int&__nobjs)
{
char* __result;
size_t __total_bytes = __size * __nobjs;
size_t __bytes_left = _S_end_free - _S_start_free; // 内存池剩余空间
if (__bytes_left >= __total_bytes) { // 内存池剩余空间完全满足需求
__result= _S_start_free;
_S_start_free+= __total_bytes;
return(__result);
} else if (__bytes_left >= __size) { // 内存池剩余空间不能完全满足需求,但足够供应一个(含)以上的区块
__nobjs= (int)(__bytes_left/__size);
__total_bytes= __size * __nobjs;
__result= _S_start_free;
_S_start_free+= __total_bytes;
return(__result);
} else { // 内存池剩余空间连一个区块的大小都无法提供
size_t __bytes_to_get =
2 *__total_bytes + _S_round_up(_S_heap_size >> 4);
//Try to make use of the left-over piece.
//把内存池当前剩下的一些小残余零头利用一下。
if (__bytes_left > 0) {
_Obj*__STL_VOLATILE* __my_free_list =
_S_free_list+ _S_freelist_index(__bytes_left); // 这里对吗?假如__bytes_left =15,则_S_freelist_index(15) = 1,
//即16B的位置,而实际上只剩下了15B?
((_Obj*)_S_start_free)-> _M_free_list_link = *__my_free_list;
*__my_free_list= (_Obj*)_S_start_free;
}
_S_start_free= (char*)malloc(__bytes_to_get);
if (0 == _S_start_free) {
size_t __i;
_Obj*__STL_VOLATILE* __my_free_list;
_Obj*__p;
//Try to make do with what we have. That can't
//hurt. We do not try smaller requests, since that tends
//to result in disaster on multi-process machines.
for (__i = __size;
__i<= (size_t) _MAX_BYTES;
__i+= (size_t) _ALIGN) {
__my_free_list= _S_free_list + _S_freelist_index(__i);
__p= *__my_free_list;
if (0 != __p) {
*__my_free_list= __p -> _M_free_list_link;
_S_start_free= (char*)__p;
_S_end_free= _S_start_free + __i; // 这里确定每一块内存大小都是__i吗?
return(_S_chunk_alloc(__size,__nobjs));
//Any leftover piece will eventually make it to the
//right free list.
}
}
_S_end_free= 0; // In case of exception.
_S_start_free= (char*)malloc_alloc::allocate(__bytes_to_get);
//This should either throw an
//exception or remedy the situation. Thus we assume it
//succeeded.
}
_S_heap_size+= __bytes_to_get;
_S_end_free= _S_start_free + __bytes_to_get;
return(_S_chunk_alloc(__size,__nobjs));
}
}可以看到chunk_alloc函数的输入有两个:1. int&__nobjs,待分配的元素个数;2. size_t __size,每个元素的大小。
chunk_alloc函数的程序流程图(为了方便观察,画的并不是标准的程序流程图)如下:
2.SGI STL第二级空间配置器__default_alloc_template的chunk_alloc函数
标签:
原文地址:http://blog.csdn.net/chengonghao/article/details/51346511