1. 程式人生 > >STL原始碼分析之第一級配置器

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_han# 第一級配置器dler)();
  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用函式重新進行了封裝, 同時一級還是二級都做了統一的介面. 接下來我們繼續分析第二級配置器.