STL初探——__default_alloc_template内存池
Posted Forever-Road
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL初探——__default_alloc_template内存池相关的知识,希望对你有一定的参考价值。
_S_chunk_alloc() 函数负责从内存池取出空间给free-list,如果内存池内存充足,则直接拿出足够的内存块给自由链表,如果内存不够所有需求但是对一小块需求能满足,则拿出一小块内存给自由链表并返回,如果一点儿内存也没有,则进行遍历压榨,最终如果真的没有,就只能求助于第一级配置器。代码如下:
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); //利用剩下的一点点零头. if (__bytes_left > 0) { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__bytes_left); ((_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; //看free-list是否还有内存区块 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; return(_S_chunk_alloc(__size, __nobjs)); //反复压榨内存 } } //执行到了这一步,说明没内存了,_S_end_free初始化置于零,并调用第一级配置器配置内存重新设定_S_start_free。 _S_end_free = 0; _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get); } _S_heap_size += __bytes_to_get; _S_end_free = _S_start_free + __bytes_to_get; // return(_S_chunk_alloc(__size, __nobjs)); } }
为了好懂,我们这样想,假设程序开始运行,客端就开始调用_S_chunk_alloc(32,20)函数,假设 malloc() 一次性配置40个32bytes的内存区块,其中20个作为函数返回值,之后1个被交给客户端,剩下19个交给 free-list[3] 维护,要的时候再去取即可。另外20个留给内存池。接下来客端调用_S_chunk_alloc(64,20),64个是归 free-list[7] 维护的,然而 free-list[7] 空空如也,必须向内存池寻求支持,内存池能够供应 20 x 32 / 64 = 10个区块,就把这10个区块返回,其中1个交给客户端,剩下九个交给 free-list[7] 维护,内存池空了,假设接下来再调用 _S_chunk_alloc(96,20) ,64个是归 free-list[11] 维护的,然而 free-list[11] 空空如也,必须向内存池寻求帮助,而内存池也是空的,于是又开始调用 malloc() 分配 20 +n 个 96大小的内存块,其中20内存块返回,一个被交付,剩下19个交给 free-list[11] 维护,而还有n个 96 大小的内存块就交给内存池维护......
如果最终内存里面的堆区没有内存了,无法为内存池注入新的内存,malloc() 行动失败,_S_chunk_alloc()就在free-list里寻找有没有 “尚未应用区块,且区块足够大”,找到就挖出一块并交出,找不到就调用第一级配置器,第一级配置器其实也是用 malloc() 来配置内存,但它有 out-of-memory 处理机制(类似new handler),或许有机会释放其他的内存并拿来此处使用,如果可以就内存配置成功,否则就抛出 bad_alloc()异常。
以上是关于STL初探——__default_alloc_template内存池的主要内容,如果未能解决你的问题,请参考以下文章