STL源码分析之第一级配置器

前言

上一节我们分析了空间配置器对new的配置, 而STL将空间配置器分为了两级, 第一级是直接调用malloc分配空间, 调用free释放空间, 第二级三就是建立一个内存池, 小于128字节的申请都直接在内存池申请, 不直接调用mallocfree.

本节我们就先分析第一种空间配置器, 直接调用malloc, free, 而STL有是怎样的封装处理.

一级配置器

一级配置器的类. 它无template型别参数. 这里我将public定义的函数和私有成员函数成对分离出来讲解.

// 一级配置器
template <int inst>
class __malloc_alloc_template 
{
  // 这里private里面的函数都是在内存不足的时候进行调用的
  private:   
    static void *oom_malloc(size_t);        // 分配不足
    static void *oom_realloc(void *, size_t);   // 重新分配不足
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    static void (* __malloc_alloc_oom_handler)();   // 内存不足设置的处理例程, 默认设置的是0, 表示没有设置处理例程, 这个处理例程是由用户手动设置的
#endif
  public:
};

唯一比较麻烦的就是set_malloc_handler 它就是接受一个函数指针, 用来保存用户自定义的处理函数, 如果用户没有设置的话, 默认就设置为0. 因为处理函数会跟后面的内存不足有关系.

// 这里是模仿c++的set_new_handler. 是由用户自己定义的处理函数, 没有设置默认为0
static void (* set_malloc_handler(void (*f)()))()
{
      void (* old)() = __malloc_alloc_oom_handler;
      __malloc_alloc_oom_handler = f;
      return(old);
}

默认将处理例程设置为0, 只有用户自己设置.

template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;

allocate

allocate : 很明显, 这里直接调用malloc分配内存, 当内存不足的时候, 程序继续调用oom_malloc来选择抛出异常还是一直申请内存, 直到申请内存成功.

// 在分配和再次分配中, 都会检查内存不足, 在不足的时候直接调用private中相应的函数
static void * allocate(size_t n)
{
      void *result = malloc(n);
      if (0 == result) result = oom_malloc(n);
      return result;
}

oom_malloc函数功能 : 除非用户自定义了处理例程, 否则当内存不足的时候直接输出内存不足的提示然后直接调用exit(1);
用户定义了处理程序, 函数会一直进行内存申请, 直到申请到内存为止

template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
  void (* my_malloc_handler)();
  void *result;
    // 用户自定义处理例程, 就一直申请内存, 否则抛出异常
  for (;;) 
  {
    my_malloc_handler = __malloc_alloc_oom_handler;
    if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
    (*my_malloc_handler)();
    result = malloc(n);
    if (result) return(result);
  }
}

deallocate

一级配置器直接调用free释放内存

static void deallocate(void *p, size_t /* n */)
{
      free(p);
}

reallocate

下面的函数都是很简单的或是重复的功能, 就一笔带过.

这里reallocate和oom_realloc和上面allocate一样的, 这里就不做过多的解释了.

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
      void * result = realloc(p, new_sz);
      if (0 == result) result = oom_realloc(p, new_sz);
      return result;
}
template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
  void (* my_malloc_handler)();
  void *result;

  for (;;) {
    my_malloc_handler = __malloc_alloc_oom_handler;
    if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
    (*my_malloc_handler)();
    result = realloc(p, n);
    if (result) return(result);
  }
}

程序默认定义mallo_alloc函数, 并且设置统一的调用接口, 默认的的接口为第二级配置器

// 默认将malloc_alloc设为0;
typedef __malloc_alloc_template<0> malloc_alloc;

统一的接口

定义符合STL规格的配置器接口, 不管是一级配置器还是二级配置器都是使用这个接口进行分配的

// 定义符合STL规格的配置器接口, 不管是一级配置器还是二级配置器都是使用这个接口进行分配的
template<class T, class Alloc>
class simple_alloc {
  public:
    static T *allocate(size_t n)
    { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
    static T *allocate(void)
    { return (T*) Alloc::allocate(sizeof (T)); }
    static void deallocate(T *p, size_t n)
    { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
    static void deallocate(T *p)
    { Alloc::deallocate(p, sizeof (T)); }
};

总结

本节对STL的第一级配置器做了分析, STL对malloc和free用函数重新进行了封装, 同时一级还是二级都做了统一的接口. 接下来我们继续分析第二级配置器.

posted @ 2018-12-06 19:03  倔强的铃铛  阅读(187)  评论(0编辑  收藏  举报