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()异常。

时间: 2024-10-25 14:01:02

STL初探——__default_alloc_template内存池的相关文章

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

SGI STL 第二级配置器使用的是memory pool,即内存池,相比较于第一级空间配置器,第二级空间配置器多了许多限制,主要是为了防止申请小额区块过多而造成内存碎片.当然小额区块在配置时实际上是对空间配置器效率的一种伤害.另外,索求任何一块内存,都得需要一些额外内存来进行标记,虽然这些标记占内存很小很小,但蚂蚁多咬死象,小区块多了,这些小标记还是挺浪费内存的,但这也无法避免,毕竟系统需要靠这些小标记管理内存. SGI 第二级配置器的做法是,如果区块足够大,超过128bytes时,就移交第一

STL源码分析之内存池

前言 上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析一下 内存池 static data template的初始化 template <bool threads, int inst> char *__default_alloc_template<threads, inst>::start_free = 0; // 内存池的首地址 tem

C++技术问题总结-第8篇 STL内存池是怎么实现的

STL内存池机制,使用双层级配置器.第一级采用malloc.free,第二级视情况采用不同策略.这种机制从heap中要空间,可以解决内存碎片问题. 1.内存申请流程图 简要流程图如下. 2.第二级配置器说明 第二级配置器目的解决小型区块造成的内存碎片问题. 使用自由链表(free-list)技巧.主动将任何小额区块的内存需求量上调至8的倍数.如需求30,则上调至32. free-list节点结构 union obj { union obj* free_list_link; char client

一个依靠STL vector的接口进行申请和回收管理的内存池类( c++ 封装)

其他出现两次,只有一个出现一次的那道题我就不更了,直接抑或,最后的结果就是那个数.为什么可以这样做呢?因为一个32位int,如果所有数都出现了两次,那么为1的那些位统计的个数一定是2的倍数,抑或之后全变成0.一个数出现了一次,它为1的那些位上,1的个数必定是奇数,抑或之后一定还是1. 我之前知道出现两次这个题的解法,但是理解的不够深,以为抑或是关键,其实不是,出现了偶数次才是关键.理解了这点,推广到出现3次上,如果所有的出现了三次,那么为1的那些位1的个数一定是三的倍数,那如果有一个数出现了一次

STL源码剖析——空间配置器Allocator#3 自由链表与内存池

上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refill()函数——重新填充自由链表 前情提要,从上节第二级配置器的源码中可以看到,在空间配置函数allocate()中,当所需的某号自由链表为空时,才会调用refill()函数来填充链表.refill()函数默认申请20块区块的内存(5行),但所得内存不一定就是20块,要看当前内存池的剩余情况和堆容量的

自己动手实现STL 01:内存配置器的实现(stl_alloc.h)

一.前言 在STL中,容器是其中的重中之重,基本的STL中的算法,仿函数等都是围绕着容器实现的功能.而,内存配置器,是容器的实现的基础.所以,我第一次要去编写便是内存配置器的实现.在STL中,内存配置器的实现是在stl_alloc.h中. 二.配置器原理简要介绍 在SGI STL中配置分为两级,第一级配置器和第二级配置器.两者关系如下: 图1:第一级配置器和第二级配置器 在SGI STL中内存的配置器分为两级,第一级配置器和第二级配置器.第一级配置器就是,直接调用系统的malloc分配内存.对于

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

PostGreSQL--内存上下文(内存池)

背景 原文链接:http://blog.csdn.net/ordeder/article/details/31768749 看了几个内存池的设计,如python,STL,基本上对内存的管理有两种结构: 1.block,即内存块,一般和内存页(pagesize)大小相关. 2.chunk,即内存分片,即在该内存块上分配要使用的内存空间. 例如python的pyIntObject中使用到的缓冲池的实现: http://blog.csdn.net/ordeder/article/details/253

高性能之内存池

内存池(Memory Pool)是一种内存分配方式. 通常我们习惯直接使用new.malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能.内存池则是在真正使用内存之前,先申请分配一定数量的.大小相等(一般情况下)的内存块留作备用.当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存.这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升. (1)针对特殊情况,例如需要频繁分配释放固定大