STL源码解析笔记(1)--空间配置器

2 篇文章 0 订阅

空间配置器(allocator)


文件组成

STL的空间配置器定义于<memeory>之中,SGI版本的<memory>中则含有2个文件:

  #include<stl_alloc.h>
  #include<stl_construct.h>

同时还有一些辅助copy和fill大块内存数据的全局函数则定义在<stl_uninitialized.h>之中


<stl_construct.h>

构造和解析的基本工具:construct() 和 destroy()

#include <new.h> //palcement new 的实现在该文件中

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

//destory()重载1 接受一个指针
template <class T>
inline void destroy(T* pointer) {
    pointer->~T();
}

//destory()重载2 接受2个iterator 根据不同__type_traits<>采取最适当措施
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
  __destroy(first, last, value_type(first));
}
//通过__destory()来获取value type
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
  typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
  __destroy_aux(first, last, trivial_destructor());
}
//__false_type即有non-trivial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
  for ( ; first < last; ++first)
    destroy(&*first);
}
//__true_type即有 trivial destructor
//如果大范围的调用trivial析构函数对效率是一种伤害
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

//针对char* 和 wchar_t*的特化版本
inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}

<stl_alloc.h>

在一段程序执行过程中,向系统申请内存这一操作一般是一段程序执行效率的瓶颈,每一次系统响应内存申请的中断对计算机资源都是一种较大的开销。因此,在SGI版本的STL中设计了2级空间配置器,旨在降低频繁申请小段内存时的开销,同时降低内存碎片会带来的影响。
此处代码未涉及多线程实现,仅讨论单线程下空间配置器的简易实现。

#ifndef MY_STL_ALLOC
#define MY_STL_ALLOC
#endif
//略去一些STL内置的宏定义以及一些为适应不同环境的代码
//改变了一些源代码的变量名称提高可读性
//仅实现2级空间配置器的核心功能
#include"my_stl_construct.h"

#include <iostream>
#define __THROW_BAD_ALLOC std::cerr << "out of memory" << std::endl; exit(1)


#ifndef __ALLOC
#define __ALLOC alloc
#endif

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
namespace mystd{

    //一级空间配置器
    //用于配置申请大于128Kb空间的内存段
    class __first_alloc_template{
    private:
        //不同情况下内存不足的handel
        static void * out_of_memeory_malloc(size_t);
        static void * out_of_memeory_realloc(void *,size_t);
        static void (* __malloc_alloc_out_of_memory_handler)();

    public:
        //第一级空间配置器直接使用malloc()
        static void * allocate(size_t n){
            void *result = malloc(n);
            if(result == 0) result = out_of_memeory_malloc(n);
            return result;
        }
        //第一级空间配置器直接使用free()
        static void deallocate(void *p){
            free(p);
        }
        //第一级空间配置器直接使用realloc()
        static void * reallocte(void *p, size_t new_size){
            void * result = realloc(p, new_size);
            if(result == 0) result = out_of_memeory_realloc(p, new_size);
        }
        //允许使用不同的自定义out_of_memeory的handle函数
        static void (* set_malloc_handler(void (*f)()))(){
            void (* old_handler)() = __malloc_alloc_out_of_memory_handler;
            __malloc_alloc_out_of_memory_handler = f;
            return (old_handler);
        }
    };


    void * __first_alloc_template::out_of_memeory_malloc(size_t n){
        void (*my_malloc_handler)();
        void *result;

        for (;;) {//不断尝试释放、配置、再释放、再配置
            my_malloc_handler = __malloc_alloc_out_of_memory_handler;
            if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
            //若未自定义out_of_memeory的handle函数则使用默认的中断
            (*my_malloc_handler)();
            result = malloc(n);
            if (result) return (result);
        }
    }

    void * __first_alloc_template::out_of_memeory_realloc(void * p,size_t n){
        void (*my_malloc_handler)();
        void *result;

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



    typedef __first_alloc_template my_malloc_alloc;



/*第一级空间配置器不直接使用new来配置内存一个原因是历史遗留因素
 *一个原因时可以直接使用set_new_handler()不需要为C++的new特别实现一个版本
 *handler应该是一个void(*p)()的函数指针
 *同时这里也提醒了使用者设置内存不足的handler是使用者的责任
 */


//第二级空间配置器作为STL空间配置器的精髓,设置了内存池的机制来降低内存碎片带来的影响,
//同时也引进了管理内存块的overhead,管理的区块越小带来的overhead越大
    class __second_alloc_template {
    private:
        enum {__ALIGN = 8};      //每个小型区块类型的边界划分
        enum {__MAX_BYTES = 128};//最大的小型区块上界
        enum {__NUMBER_OF_FREE_LIST = __MAX_BYTES/__ALIGN};//free_list的数量

        //将请求的bytes上调至8的倍数
        static size_t ROUND_UP(size_t bytes) {
            return (((bytes) + __ALIGN - 1) & ~(__ALIGN - 1));
        }
        //确定请求的小型内存块大小类型
        static  size_t FREELIST_INDEX(size_t bytes) {
              return (((bytes) + __ALIGN-1)/__ALIGN - 1);
        }
    public:
        //每个free_list的节点构造
        union free_list_node{
            free_list_node* next;
            char client_data[1];
        };
    private:
        //维护16个不同大小free_list(8到128中8的倍数)当表头为空时则说明没有可用内存块
        static free_list_node *free_list[__NUMBER_OF_FREE_LIST];
        //填充内存池
        static void * refill(size_t n);
        //每次通过一级空间配置器申请大块内存为number_nodes*size大小
        static char * chunk_alloc(size_t size, int &number_nodes);

        static char *start_free;//内存池起始位置
        static char *end_free;  //内存池结束位置
        static size_t heap_size;//当前堆的大小

    public:
        static void * allocate(size_t n);
        static void deallocate(void *p, size_t n);
        static void * reallocate(void *p, size_t old_sz, size_t new_sz);
    };

    //内存池参数初始化
    __second_alloc_template::free_list_node *
        __second_alloc_template::free_list[__NUMBER_OF_FREE_LIST] =
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    char* __second_alloc_template::start_free = 0;
    char* __second_alloc_template::end_free = 0;
    size_t __second_alloc_template::heap_size = 0;

    //该函数每次申请连续大段内存块放入内存池中
    char * __second_alloc_template::chunk_alloc(size_t size, int &number_nodes){
        char * result;
        size_t total_bytes = size * number_nodes;//待申请的内存块大小
        size_t bytes_left = end_free - start_free;//当前内存池剩余的内存块大小

        if (bytes_left >= total_bytes) {//内存池中内存满足申请的内存大小直接拨出
            result = start_free;
            start_free += total_bytes;
            return(result);
        } else if (bytes_left >= size) {
        //如果不能够完全满足当前需求但能够提供一个以上的内存块则不额外申请内存块
            number_nodes = bytes_left/size;
            total_bytes = size * number_nodes;
            result = start_free;
            start_free += total_bytes;
            return(result);
        } else {
            //每次申请大小为当前需求量的2倍加上heap大小的十六分之一这溢出值会使得heap越来越大
            //以减少chunk_alloc()的调用次数
            size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
            //如果内存池中的仍有剩余的小块内存则插入合适大小的free_list中
            if (bytes_left > 0) {
                free_list_node * *my_free_list = free_list + FREELIST_INDEX(bytes_left);
                ((free_list_node *)start_free) -> next = *my_free_list;
                *my_free_list = (free_list_node *)start_free;
            }
            start_free = (char *)malloc(bytes_to_get);
            //如果没有这么大的内存块尝试从现有free_list中查找满足当前一个size需求的空内存块回收
            //并递归调用自身来重新尝试分配
            if (0 == start_free) {
                int i;
                free_list_node * *my_free_list, *p;
                for (i = size; i <= __MAX_BYTES; i += __ALIGN) {
                    my_free_list = free_list + FREELIST_INDEX(i);
                    p = *my_free_list;
                    if (0 != p) {
                        *my_free_list = p -> next;
                        start_free = (char *)p;
                        end_free = start_free + i;
                        //递归调用来修正number_nodes参数
                        return(chunk_alloc(size, number_nodes));
                    }
                }
                end_free = 0;
                start_free = (char *)my_malloc_alloc::allocate(bytes_to_get);
                //调用一级空间配置器希望通过out_of_memory_handler来抛出异常或者改善当前情况
            }
            heap_size += bytes_to_get;
            end_free = start_free + bytes_to_get;
            //递归调用来填充内存池
            return(chunk_alloc(size, number_nodes));
        }
    }


    void* __second_alloc_template::refill(size_t n){
        int number_nodes = 20;
        char * chunk = chunk_alloc(n, number_nodes);
        free_list_node * *my_free_list;
        free_list_node * result;
        free_list_node * current_free_list_node, * next_free_list_node;
        int i;

        if (number_nodes == 1) return(chunk);
        //如果申请的内存块只够满足当前一个内存块需求则直接返回
        //填充除了第一个内存块剩余的内存块到free_list之中
        my_free_list = free_list + FREELIST_INDEX(n);
        result = (free_list_node *)chunk;
        *my_free_list = next_free_list_node = (free_list_node *)(chunk + n);
        for (i = 1; i < number_nodes; i++) {
            current_free_list_node = next_free_list_node;
            next_free_list_node = (free_list_node *)((char *)next_free_list_node + n);
            current_free_list_node -> next = next_free_list_node;
        }
        current_free_list_node -> next = 0;
        return(result);
    }

    void * __second_alloc_template::allocate(size_t n){
        free_list_node * *my_free_list;
        free_list_node * result;
        if (n > (size_t) __MAX_BYTES){//大于小型内存块上界则调用一级空间配置器
            return (my_malloc_alloc::allocate(n));
        }
        my_free_list = free_list + FREELIST_INDEX(n);
        result = *my_free_list;
        if (result == 0) {
            //如果该类型小型内存块的链表内没有可用的内存块节点,则调用refill()填充该链表
            void *r = refill(ROUND_UP(n));
            return r;
        }
        *my_free_list = result->next;
        //从该类型小型内存块链表中移除该块内存
        return (result);
    }

    void __second_alloc_template::deallocate(void *p, size_t n){
        free_list_node *q = (free_list_node *)p;
        free_list_node * *my_free_list;

        if (n > (size_t) __MAX_BYTES) {
        //若该块大于128kb则不放入内存池中直接释放
            my_malloc_alloc::deallocate(p);
            return;
        }
        //若该内存块可用则回收插入到内存块链表的表首
        my_free_list = free_list + FREELIST_INDEX(n);
        q -> next = *my_free_list;
        *my_free_list = q;
    }

    void* __second_alloc_template::reallocate(void *p, size_t old_size, size_t new_size){
        void* result;
        size_t copy_size;
        if (old_size > (size_t) __MAX_BYTES && new_size > (size_t) __MAX_BYTES){
        //如果重新分配前和分配后大小均大于128kb则调用一级空间分配器
            return realloc(p, new_size);
        }
        //重新分配前后大小不变则直接返回
        if (ROUND_UP(old_size) == ROUND_UP(new_size)) return (p);
        //新分配的内存大小如果是小型内存块则从内存池中获取并释放原有内存块
        result = allocate(new_size);
        copy_size = new_size > old_size? old_size : new_size;
        memcpy(result, p, copy_size);
        deallocate(p, old_size);
        return (result);
    }

    typedef __second_alloc_template my_alloc;

    //为了满足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)); }
    };
}

<uninitialized.h>

该文件主要实现了3个内存处理函数uninitialized_copy() uninitialized_fill() uninitialized_fill_n() 对于POD类型的元素实际上则分别对应于高层次函数copy() fill() fill_n() 都是STL的算法

#define __STL_TRY try
#define __STL_UNWIND(action) catch(...) { action; throw; }


//对给定的输入范围[first,last)内的内存空间依次在result所指向的空间内构造相同的元素
template <class InputIterator, class ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result) {
  return __uninitialized_copy(first, last, result, value_type(result));
}
//根据是否为POD类型选择优化特定的实现
template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator __uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, T*) {
  typedef typename __type_traits<T>::is_POD_type is_POD;
  return __uninitialized_copy_aux(first, last, result, is_POD());
}
//如果是POD类型直接使用copy()函数节省多次调用construct()的开销
template <class InputIterator, class ForwardIterator>
inline ForwardIterator __uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, __true_type) {
  return copy(first, last, result);
}
//如果不是POD类型则在输入范围内依次构造元素
template <class InputIterator, class ForwardIterator>
ForwardIterator __uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, __false_type) {
  ForwardIterator cur = result;
  __STL_TRY {
    for ( ; first != last; ++first, ++cur)
      construct(&*cur, *first);
    return cur;
  }
  __STL_UNWIND(destroy(result, cur));
}

//针对char* 和 wchar_t* 特化实现
inline char* uninitialized_copy(const char* first, const char* last, char* result) {
  memmove(result, first, last - first);
  return result + (last - first);
}

inline wchar_t* uninitialized_copy(const wchar_t* first, const wchar_t* last, wchar_t* result) {
  memmove(result, first, sizeof(wchar_t) * (last - first));
  return result + (last - first);
}

//将给定的first空间内n个元素copy到result指定的空间内
template <class InputIterator, class Size, class ForwardIterator>
inline pair<InputIterator, ForwardIterator> uninitialized_copy_n(InputIterator first, Size count, ForwardIterator result) {
  return __uninitialized_copy_n(first, count, result, iterator_category(first));
}

template <class InputIterator, class Size, class ForwardIterator>
pair<InputIterator, ForwardIterator> __uninitialized_copy_n(InputIterator first, Size count, ForwardIterator result, input_iterator_tag) {
  ForwardIterator cur = result;
  __STL_TRY {
    for ( ; count > 0 ; --count, ++first, ++cur)
      construct(&*cur, *first);
    return pair<InputIterator, ForwardIterator>(first, cur);
  }
  __STL_UNWIND(destroy(result, cur));
}

template <class RandomAccessIterator, class Size, class ForwardIterator>
inline pair<RandomAccessIterator, ForwardIterator> __uninitialized_copy_n(RandomAccessIterator first, Size count, ForwardIterator result, random_access_iterator_tag) {
  RandomAccessIterator last = first + count;
  return make_pair(last, uninitialized_copy(first, last, result));
}





//将指定空间[first,last)内用x值填满
template <class ForwardIterator, class T>
inline void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x) {
  __uninitialized_fill(first, last, x, value_type(first));
}
//根据是否为POD类型选择优化特定的实现
template <class ForwardIterator, class T, class T1>
inline void __uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x, T1*) {
  typedef typename __type_traits<T1>::is_POD_type is_POD;
  __uninitialized_fill_aux(first, last, x, is_POD());

}
//如果是POD类型直接使用fill()函数节省多次调用construct()的开销
template <class ForwardIterator, class T>
inline void __uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, __true_type)
{
  fill(first, last, x);
}
//如果不是POD类型则在输入范围内依次构造x元素
template <class ForwardIterator, class T>
void __uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, __false_type)
{
  ForwardIterator cur = first;
  __STL_TRY {
    for ( ; cur != last; ++cur)
      construct(&*cur, x);
  }
  __STL_UNWIND(destroy(first, cur));
}

//将指定空间[first,first+n)内用x值填满
template <class ForwardIterator, class Size, class T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x) {
  return __uninitialized_fill_n(first, n, x, value_type(first));
}

//根据是否为POD类型选择优化特定的实现
template <class ForwardIterator, class Size, class T, class T1>
inline ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n, const T& x, T1*) {
  typedef typename __type_traits<T1>::is_POD_type is_POD;
  return __uninitialized_fill_n_aux(first, n, x, is_POD());

}

//如果是POD类型直接使用fill_n()函数节省多次调用construct()的开销
template <class ForwardIterator, class Size, class T>
inline ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, __true_type) {
  return fill_n(first, n, x);
}
//如果不是POD类型则在输入范围内依次构造x元素
template <class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, __false_type) {
  ForwardIterator cur = first;
  __STL_TRY {
    for ( ; n > 0; --n, ++cur)
      construct(&*cur, x);
    return cur;
  }
  __STL_UNWIND(destroy(first, cur));
}







// copies [first1, last1) into [result, result + (last1 - first1)), and
// copies [first2, last2) into [result, result + (last1 - first1) + (last2 - first2)).

template <class InputIterator1, class InputIterator2, class ForwardIterator>
inline ForwardIterator
__uninitialized_copy_copy(InputIterator1 first1, InputIterator1 last1,
                          InputIterator2 first2, InputIterator2 last2,
                          ForwardIterator result) {
  ForwardIterator mid = uninitialized_copy(first1, last1, result);
  __STL_TRY {
    return uninitialized_copy(first2, last2, mid);
  }
  __STL_UNWIND(destroy(result, mid));
}

// Fills [result, mid) with x, and copies [first, last) into [mid, mid + (last - first)).
template <class ForwardIterator, class T, class InputIterator>
inline ForwardIterator
__uninitialized_fill_copy(ForwardIterator result, ForwardIterator mid,
                          const T& x,
                          InputIterator first, InputIterator last) {
  uninitialized_fill(result, mid, x);
  __STL_TRY {
    return uninitialized_copy(first, last, mid);
  }
  __STL_UNWIND(destroy(result, mid));
}

// copies [first1, last1) into [first2, first2 + (last1 - first1)), and
//  fills [first2 + (last1 - first1), last2) with x.
template <class InputIterator, class ForwardIterator, class T>
inline void __uninitialized_copy_fill(InputIterator first1, InputIterator last1,
                          ForwardIterator first2, ForwardIterator last2, const T& x) {
  ForwardIterator mid2 = uninitialized_copy(first1, last1, first2);
  __STL_TRY {
    uninitialized_fill(mid2, last2, x);
  }
  __STL_UNWIND(destroy(first2, mid2));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值