• STL源码剖析--空间配置器心得笔记


    定义:空间配置器就是分配空间的操作的组件.

    先介绍两个接口函数

    设计一个STL的空间配置器有有一些必要的接口,这里就不一一列举,列举两个在书中的全局函数

    第一个是constuct()负责构造用的.

    template <class T1, class T2>
    inline void _construct(T1* p, const T2& value){
        new(p) T1(value);
    }

    上面代码是_construct(),因为constuct()对_construst()做了包装.

    new(p) T1(value)这里是placement new.需要包含头文件#include<new> 相当于p指向的内存空间创建一个T1对象,然后把T2强转给T1,会调用T1的构造函数.

    优点:相当于把已有空间当成缓冲区,减少分配空间耗费时间,因为直接new去找空闲空间位置比较耗费时间.

    第二个是destroy()负责析构用的.

    对于destroy有两个重载版本,一个是对一个destory,则直接调用析构函数,另外一个是对一段destory,不会直接调用析构函数,而是先取得type_value,

    再利用__type_traits<T>判断此型别是否无关痛痒,若返回__ture_type则说明无关痛痒,什么也不做,若返回__flase_type则必须调用循环将一段对象析构.

    因为如果范围很大且都无关痛痒,这样就节省了时间.

    两个空间配置器

    SGI STL中包含两个空间配置器:

    第一个是std::allocator,但这个效率不佳,只是对::operator new和::operator delete做一层薄薄的包装.

    这里不做详细说明.

    第二个是std::alloc,是SGI STL默认的空间配置器,其中实现采用了内存池,对于分配大量小容量的对象,可以大大减少内存碎片。

    下面做详细解释.

    std::alloc中又含有有第一级配置器和第二级配置器.默认是第二级配置器,是通过预处理语句#ifdef __USE_MALLOC确定的,__USE_MALLOC未定义.

    无论是第一级还是第二级空间配置器,SGI STL定义了一个simple_alloc对外接口包装了一下.

    第一级配置器(__malloc_alloc_template)

    第一级配置器是使用malloc(),free(),realloc()等c函数执行实际的内存配置,释放,重配置的操作.也实现了类似于c++中的new-handler机制.

    new-handle机制是指,若需求的内存配置无法满足时会不断地调用一个你指定的函数new-handle,当满足内存仍然不满足需求或者未设定"内存不足处理例程"时,

    将抛出bad_alloc异常.

    第二级配置器(__default_alloc_template)

    若当前区块大于128bytes时,调用第一级,反之调用内存池管理.这样的优点是避免了太多小额区块造成内存的碎片,增加配置时的额外负担.

    内存池是实现机制是维护16个free-lists,各自管理的大小是其8的倍数,free-lists的实质是链表,这个链表是由union定义的,这样做的好处是,不会为了维护链表所必须的指针而造成内存的浪费.

    内存池的实现

    主要介绍有三个函数:

    空间配置函数allocate()

    当发现大于128则调用第一级配置器的allocate,否则看有无可用的free-lists,如果有就用一个类似于链表的删除操作,分配内存.因为是从free-lists中拿内存分配嘛.否则就调用refill().

    空间释放函数deallocate()

    当发现大于128则调用第一级配置器deallocate,否则就用一个类似于链表的插入操作,将区块回收.

    重新填充函数

    前面提到的refill()函数调用chunk_alloc(),chunk_alloc默认从内存池中取出20大小的节点.里面的机制大概是,如果内存池够,则调出20个区块,如果不够,且至少能满足一个,则返回一个.
    如果完全没有则需要利用malloc从heap中获取内存.如果整个heap也没有内存,则去四处去其他大于当前等级的free-lists找尚未用区块.找到了就用,否则去第一级配置器找,虽然第一级配置器也是用malloc分配内存的但是其中有set-new-handle机制.

    最后介绍了五个内存处理工具

    前面两个constuct和destory已经讲过了.

    剩下三个都是对为初始化区域初值填写,只不过区域的描述不同,都具备"commit or rollback"语意,意思是要么构造全部,如果有一个失败则都不构造.

    下面是详细对比:

    1.uninitialized_fill_n(first,n,x) first到first+n-1填写x

    先用__type_traits<T1>::is_POD_type判断是否为POD型别,POD型别是指必然拥有trivialctor/dtor/copy/assignment函数.所以可以用一些高效的初值填写操作,如果是__true_type,则调用fill_n(),否则一一调用construct().

    2.uninitialized_fill(first,last,x) first到last-1填写x

    先用__type_traits<T1>::is_POD_type判断是否为POD型别,如果是__true_type,则调用fill(),否则一一调用construct().

    3.uninitialized_copy(first,last,result)将result到result后面last-first-1的赋初值为[first,last)的对象

    先用__type_traits<T1>::is_POD_type判断result是否为POD型别,如果是__true_type,则调用copy(),否则一一调用construct().

    uninitialized_copy针对char*和wchar*有两个特化版本,采用memmove(直接移动内存内容)来执行复制行为,更加高效.

    每天进步一点点!!!

  • 相关阅读:
    xpath json操作符说明
    搜索引擎下拉词接口
    利用jsonp调用外部ip地址池
    excel支持正则表达式提取字符函数(支持RegExp捕获分组)
    【竞价网站绝技】根据访客ip,页面显示访客所属城市的html代码(借用YY IP地址库)
    关于百度信息流“霸屏”代码(着落页点击浏览器“回退”按钮还是在官网)的实现。
    关于免费虚拟主机sanfengyun
    typescript interface接口
    typescript 声明和解构
    typescript 基础数据类型
  • 原文地址:https://www.cnblogs.com/2462478392Lee/p/14090866.html
Copyright © 2020-2023  润新知