STL一级空间配置器

提纲:本文主要分析STL一级空间配置器的源代码并模拟实现一级空间配置器
一、什么是STL
STL(standard Template Library,标准模板库),是算法和一些组件的结合,STL有六大组件,彼此可以组合套用,六大组件分别是
1、容器(containers):各种数据结构,如vector,list,deque,set,map等,用来存放数据。
2、算法(algorithms):各种算法如sort,search,copy,erase等。
3、迭代器(iterators):扮演容器与算法之间的胶合剂,共有五种类型。
4、仿函数(functors):行为类似函数,可作为算法的某种谋略。
5、配接器(adapters):一种用来修饰容器或仿函数或迭代器接口的东西。
6、配置器(allocators):负责空间配置与管理。
二、空间配置器
1、什么是空间配置器
整个STL操作的数值都存放在容器中,而容器是需要空间配置器来管理和分配空间的。
注:这里所指的空间不单单指内存,也可以是磁盘或者其他存储介质。
2、空间配置器的设计思想
(1)向system heap索要空间;
(2)内存不足的应变措施;
(3)解决内存碎片问题。
SGI STL设置了两级空间配置器,一级空间配置器底层用malloc()和free()来实现;二级空间配置器采用了内存池的处理方式。
三、剖析一级空间配置器源代码
1、剖析源代码
一级空间配置器以malloc(),free(),realloc()等C语言函数来实现空间的配置、释放、重配置。
我们来看具体的源代码

//一级空间配置器
template <int __inst>
class __malloc_alloc_template {

private:
//以下函数用来处理内存不足的情况
  static void* _S_oom_malloc(size_t);
  static void* _S_oom_realloc(void*, size_t);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
  //内存不足处理例程
  static void(*__malloc_alloc_oom_handler)(); //__malloc_alloc_oom_handler是函数指针
#endif

public:

  //空间配置函数
  static void* allocate(size_t __n)
  {
    //用malloc申请空间
    void* __result = malloc(__n);
    //如果申请空间失败,则调用_S_oom_malloc重新申请空间
    if (0 == __result) __result = _S_oom_malloc(__n);
    return __result;
  }

  //空间释放函数
  static void deallocate(void* __p, size_t /* __n */)
  {
      //调用free来释放空间
    free(__p);
  }

  //空间重配置函数
  static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)
  {
      //用realloc来重新配置空间
    void* __result = realloc(__p, __new_sz);
    //如果由于空间不足配置失败,则调用_S_oom_realloc重新申请空间
    if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);
    return __result;
  }

  //该函数重新指定了内存分配异常处理函数,并返回了原有的内存分配异常处理函数
  //该函数接受一个“返回值和参数均为空的函数指针”作为参数
  //该函数最后返回一个“返回值和参数均为空的函数指针”
  static void (* __set_malloc_handler(void (*__f)()))()
  {
    void (* __old)() = __malloc_alloc_oom_handler;
    //重新指定内存分配异常处理函数
    __malloc_alloc_oom_handler = __f;
    //返回原有的内存分配异常处理函数
    return(__old);
  }

};

// malloc_alloc out-of-memory handling

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int __inst>
//内存不足处理例程,初始值为0,待用户自定义,考虑内存不足时的应变措施
void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;
#endif

template <int __inst>

//申请空间失败时调用_S_oom_malloc重新申请空间
 void* __malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
     //定义一个函数指针__my_malloc_handler
    void (* __my_malloc_handler)();
    void* __result;
    //该循环有两个退出条件
    //一个是成功申请到空间,最终返回__result
    //另一个是最终申请空间失败,抛出异常__THROW_BAD_ALLOC
    for (;;) {
        __my_malloc_handler = __malloc_alloc_oom_handler;
        //由于初值为0,如果用户没有自定义内存不足处理例程,那么还是抛出异常
        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
        //调用内存不足处理例程,尝试释放空间
        (*__my_malloc_handler)();
        //再次尝试配置空间
        __result = malloc(__n);
        if (__result) return(__result);
    }
}

template <int __inst>

//重新配置空间失败时调用_S_oom_realloc申请空间
void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __p, size_t __n)
{
    //定义一个函数指针__my_malloc_handler
    void (* __my_malloc_handler)();
    void* __result;
    //该循环有两个退出条件
    //一个是成功申请到空间,最终返回__result
    //另一个是最终申请空间失败,抛出异常__THROW_BAD_ALLOC
    for (;;) {
        __my_malloc_handler = __malloc_alloc_oom_handler;
        //由于初值为0,如果用户没有自定义内存不足处理例程,那么还是抛出异常
        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
        //调用内存不足处理例程,尝试释放空间
        (*__my_malloc_handler)();
        //再次尝试配置空间
        __result = realloc(__p, __n);
        if (__result) return(__result);
    }
}

//由于参数inst在这里没有排上用场,因此定义为数值0
typedef __malloc_alloc_template<0> malloc_alloc;

2、小结
通过对源代码的剖析,我们可以看出:SGI STL一级空间配置器是通过调用malloc()函数,realloc()函数进行申请空间,当申请空间失败后便调用_S_oom_malloc()函数和_S_oom_realloc()函数重新申请空间,而这两个函数都会调用“内存不足处理例程”来尝试释放空间,期望能在某次释放空间后得到一块足够大小的内存,但是如果客户端不设定“内存不足处理例程”的话,程序便会抛出异常。

通过下图来表示我对一级空间配置器的理解:
这里写图片描述
四、模拟实现一级空间配置器
通过对以上源代码的剖析,根据自己的理解,尝试模拟实现一级空间配置器,具体代码如下

//一级空间配置器
template <int inst>
class MallocAllocTempalte
{
public:
    //分配空间
    static void* Allocate(size_t n)
    {
        void* ret = malloc(n);
        //如果申请失败就调用OOM_Malloc()函数
        if (NULL == ret)
            ret = OOM_Malloc(n);
        return ret;
    }
    //模拟C++的set_new_handler
    static void(*set_malloc_handler(void(*f)())) ()
    {
        //保存原有处理例程
        void(*old)() = MallocAllocOOMHandler;
        //重新指定内存不足处理例程
        MallocAllocOOMHandler = f;
        return old;
    }
    //处理分配空间时的内存不足情况
    void* OOM_Malloc(size_t n)
    {
        void* ret = NULL;
        while (1)
        {
            if (NULL == MallocAllocOOMHandler)
                throw bad_alloc();
            //再次处理例程,尝试释放内存
            (*MallocAllocOOMHandler)();
            //尝试重新分配内存
                ret = OOM_Malloc(n);
                if (ret)
                    return ret;
        }
    }

    //释放空间
    void Deallocate(void* p)
    {
        free(p);
    }

    //重新分配空间
    void* Reallocate(void* p, size_t n)
    {
        void* ret = Reallocate(p, n);
        if (NULL == ret)
            ret = OOM_Realloc(p, n);
        return ret;
    }
    //处理重新分配空间时的内存不足情况
    void* OOM_Realloc(void* p, size_t n)
    {
        void* ret = NULL;
        while (1)
        {
            if (NULL == MallocAllocOOMHandler)
                throw bad_alloc();
            //调用例程,尝试释放空间
            (*MallocAllocOOMHandler)();
            //再次配置空间
            ret = OOM_Realloc(p, n);
            if (ret)
                return ret;
        }
    }
private:
    //处理用malloc分配内存时内存不足的情况
    static void* OOM_Malloc(size_t);
    //处理用realloc分配内存时内存不足的情况
    static void* OOM_Realloc(void*, size_t);
    //指针MallocAllocOOMHandler指向一个无参数并且返回值也为空的函数
    static void (*MallocAllocOOMHandler) ();
};

template <int __inst>
//内存不足处理例程,初始值为0,待用户自定义,考虑内存不足时的应变措施
void(*MallocAllocTempalte<__inst>::MallocAllocOOMHandler)() = 0;

typedef MallocAllocTempalte<0> malloc_alloc;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值