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内存池的主要内容,如果未能解决你的问题,请参考以下文章

STL初探——第二级配置器 __default_alloc_template的学习心得

STL容器__简化版

STL容器__简化版

初探STL之算法

STL初探

Objective-C 源码初探 __attribute__