《STL源码剖析》读书笔记(四)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hgyan25/article/details/81205178

空间配置器 allocator

在STL中,所有的元素都是存放在容器中,容器需要配置空间来储存这些数值,因此需要用到空间配置器。

概览

  • SGI的空间配置器
    • SGI标准的空间配置器是allocator, 只是对基层内存配置/释放行为(对运算符new/delete)进行了一层薄薄的封装,没有考虑到效率上的优化。
    • SGI特殊的空间配置器是alloc,
      SGI以malloc()和free()完成内存的配置和释放。考虑到小型区块可能造成内存破碎问题,SGI设计了双层级配置器。第一层直接用malloc和free,第二级配置器视情况采用不同策略。如果配置区别大于128bytes,选用第一级配置器;当小于128bytes时,采用复杂的memory pool的整理方式。是否同时开放第二级配置器,取决于__USE_MALLOC是否被定义。

精细分工

  • STL Allocator的精细分工
    stl_construct.h
    内存配置:allocate();
    内存释放前进行对象的析构:destroy(),调用析构函数;
    stl_alloc.h
    内存配置后进行对象的构造:construct(),placement new调用构造函数;
    内存释放: deallocate();
    stl_uninitialized.h
    定义一些全域函式,用来填充(fill)或者复制(copy)大块的内存内容。

  • stl_construct.h
    construct()接收一个指针和一个初始值value,用途是将初值设定到指针所指的空间上
    destroy有两个版本,版本1接受一个指针,准备将该指针所指之物析构掉;版本2是接收first和last两个迭代器,将[first,last)范围内所有对象析构掉

  • std::alloc(设置配置器)
    SGI用malloc和free这2个C函数代替完成内存的申请和释放。考虑到内存碎片问题,SGI设计了两级配置器,第一级直接使用malloc和free,包括了内存不足处理机制,需要调用者自己提供。第二级判断配置区超过128字节,调用第一级配置器。小于128字节,采用内存池管理
    这里写图片描述
    这里写图片描述

双层级配置器

  • 第一级配置器
    __malloc_alloc_template
    SGI第一级配置器的allocate()和realloc()使用malloc与free来配置和释放内存。调用不成功后,会调用oom_malloc()和oom_realloc()。后两个函数都有内循环,不断调用“内存不足处理例程”,期待在某次调用后获得足够内存而圆满完成任务。设定“内存不足处理例程”是客端的责任。

  • 第二级配置器
    __default_alloc_template
    当区块小于128byte,交由第二级配置器处理。用内存池(memory pool)来管理。也叫次层配置(sub-allocation)

    • 实现方式

      • 每次配置一大块内存,并维护对应的自由链表
      • 如果下次有相同大小的内存需求,就从free-list中拨出
      • 如果客端释放小额区块,就由配置器回收到free-list中
      • SGI第二级配置器会主动将任何小额区块的内存需求量上调至8的倍数。它维护16个free-lists,各自管理大小分别为8,16,24,32,…,128byte的小额区块。
      • 节点结构
        //利用union的性质使得链表既是指针又是实际区块
        union obj
        {
            union obj * free_list_link;
            char client_data[1];       //柔性数组
        };
    • 内存池
      chunk_alloc的工作:从内存池中取空间给free-list使用。

      if(内存池水量足够)
          直接调出20个区块给free list
      else if(内存池水量还足够提供至少1个区块)
          调出实际能够供应的区块
      else
          利用malloc()向堆heap中配置内存,为内存池注入源头活水以应付需求。一般申请为需求量的两倍,再加上随着配置次数增加而越来越大的附加量
          if(heap的空间也不够)
              malloc()失败,调用第一级配置器中的out of memory处理机制,或许有机会释放其内存拿来此处使用。如果可以就成功,否则发出bad_alloc异常。

相关问题

  • STL里面空间分配是怎么样的?
    STL中用allocator类来实现空间分配,有一级配置器二级配置器,根据一个环境组态来确定使用哪一级的配置器。SGI STL将alloc设置为第二级配置器。

  • 如果用让你写一个STL的空间配置器,这个配置器需要经常分配大量的小内存,但大量的分配小内存会造成内存碎片,你会怎么解决这个问题?那如果用你实现的配置器分配的空间是怎么释放的?
    参考:可以说一些二级配置器是怎么实现的,可以参照STL特有的空间配置器alloc的设计

    1. 针对于小内存的问题,可以像第二级配置器一样来实现,用内存池来管理。每次配置一大块内存,然后维护16个自由链表free-lists。每个链表会维护若干个小额区块,每个小额区块的大小是8的倍数。
    2. 如果自由链表里的小额区块不够了,利用chunk_alloc(size,num),从内存池中取空间给free-list使用(参考上面的内存池内容)
    3. 如果客端申请需求量小于128byte,会将申请的内存需求量上调至8的倍数,然后再查找对应的自由链表中的小额区块。如果大于128byte,就用第一级配置器的allocate()函数,直接用malloc来配置内存。
    4. 释放内存时,如果释放量小于128byte,配置器会将它归还到对应的自由链表中。如果大于128byte,就用第一级配置器的deallocate()函数,直接用free来释放内存。

猜你喜欢

转载自blog.csdn.net/hgyan25/article/details/81205178