stl源码剖析 详细学习笔记 空间配置器

来源:互联网 发布:音乐品味分高低知乎 编辑:程序博客网 时间:2024/05/14 20:17




//---------------------------15/04/05----------------------------


/*

    空间配置器概述:

    1:new操作包含两个阶段操作

        1>调用::operator new配置内存(底层使用malloc来申请内存)

        2>调用函数的构造函数,构造对象内容。

    deltenew一样,先调用析构函数,再调用::operator delete释放内存。

    2:为了效率,stl把两个阶段分开来。

        1>内存配置操作: alloc::allocate();

        2>内存释放操作: alloc::deallocate();

        3>对象构造操作: ::construct();

        4>对象析构操作: ::destory();

    3:内存配置器的整体:

        1><stl_construct.h>     : 这里定义了全局函数construct()和的destroy()

        2><stl_alloc.h>         : 定义了一二级配置器。

        3><stl_uninitialized.h> : 定义了一些全局函数,用来填充或复制大块内存数据。

        un_initialized_copy(), un_initialized_fill(), un_initialized_fill_n()

        这些函数对效率考虑得面面俱到:最差的情况下会调用construct(),最佳的情况下会

        使用c的标准函数memmove()直接进行内存数据的移动。

 

*/


//construct() destroy()


template<class T1,class T2>

inlinevoid construct(T1* p, const T2& value)

{

   new (p) T1(value);

}


template<class T>

inlinevoid destroy(T* pointer)

{

    pointer->~T();

}


template<class ForwardIterator>

inlinevoid destroy(ForwardIterator first, ForwardIterator last)

{

    __destroy(first, last, value_type(first));

}


template<class ForwardIterator,class T>

inlinevoid __destroy(ForwardIterator first, ForwardIterator last, T*)

{

   typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;

    __destroy_aux(first, last, trivial_destructor());

}


template<class ForwardIterator>

inline void

__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)

{

   for(; first < last; ++first)

        destroy(&*first);

}


template<class ForwardIterator>

inlinevoid __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}


inlinevoid destroy(char*,char*) {}

inline void destroy(wchar_t*,wchar_t*) {}




//alloc


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));

    }

};


//第一级配置

template<int inst>

class __malloc_alloc_template

{

private:

   static void* oom_malloc(size_t);

   static void* oom_realloc(void *, size_t);

   static void (* __malloc_alloc_oom_handler)();

    

public:

    //直接调用malloc分配内存,失败就调用oom_malloc,这个函数会不断申请分配,

    //并不断调用处理函数,如果没有处理函数,就抛出错误。

   static void* allocate(size_t n)

    {

       void *result = malloc(n);

       if(0 == result)

            result == oom_malloc(n);

       return result;

    }

    

   static void deallocate(void *p, size_t)

    {

        free(p);

    }

    

   static void* reallocate(void *p, size_t, size_t new_sz)

    {

       void *result = realloc(p, new_sz);

       if(0 == result)

            result = oom_realloc(p, new_sz);

       return result;

    }

    

   static void (* set_malloc_handle(void (*f)()))()

    {

       void ( *old)() = __malloc_alloc_oom_handler;

        __malloc_alloc_oom_handler = f;

       return(old);

    }

};


template<int inst>

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



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);

    }

}


template<int inst>

void* __malloc_alloc_oom_handler<int>::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);

    }

}


typedef __malloc_alloc_template<0> malloc_alloc;



//第二级配置器


//使用union节省空间

union obj

{

   union obj * free_list_link;

   char client_data[1];

};


enum { __ALIGN =8};

enum { __MAX_BYTES =128};

enum { __NFREELISTS = __MAX_BYTES / __ALIGN};


template<bool threads,int inst>

class __default_alloc_template

{

private:

    //这里就是加7再对8取模这样写的公式扩展性比较小, 也就是__ALIGN必须取2的倍数,

    //不然这公式就不是取模操作了。

   static size_t ROUND_UP(size_t bytes)

    {

       return ((bytes) + __ALIGN - 1) & ~(__ALIGN - 1));

    }

    

   union obj

    {

       union obj *free_list_link;

       char client_data[1];

    };

    

   static obj * volatile free_list[__NFREELISTS];

   static size_t FREELIST_INDEX(size_t bytes)

    {

       return (((bytes) + __ALIGN - 1) / __ALIGN - 1));

    }

    

   static void* refill(size_t n);

   static char *chunk_alloc(size_t size,int &nobjs);

    

   static char *start_free;

   static char *end_free;

   static size_t heap_size;

    

public:

   static void* allocate(size_t n)

    {

        obj *volatile * my_free_list;

        obj * result;

        

       if(n > (size_t)__MAX_BYTES)

           return (malloc_alloc::allocate(n));

        

        my_free_list = free_list + FREELIST_INDEX(n);

        result = *my_free_list;

       if(result == 0)

        {

           void *r = refill(ROUND_UP(n));

           return r;

        }

        *my_free_list = result->free_list_link;

       return (result);

    }

    //如果比最大大小大,就交给第一级配置,否则收回到链表中

   static void deallocate(void *p, size_t n)

    {

        obj *q = (obj*)p;

        obj *volatile * my_free_list;

       if(n > (size_t)__MAX_BYTES)

        {

            malloc_alloc::deallocate(p, n);

           return;

        }

        

        my_free_list = free_list + FREELIST_INDEX(n);

        q->free_list_link = *my_free_list;

        *my_free_list = q;

        

    }

   static void* reallocate(void *p, size_t old_sz, size_t new_sz);

};


template<bool threads,int inst>

char *__default_alloc_template<threads, inst>::start_free =0;


template<bool threads,int inst>

char *__default_alloc_template<threads, inst>::end_free =0;


template<bool threads,int inst>

size_t *__default_alloc_template<threads, inst>::heap_size =0;


template<bool threads,int inst>

__default_alloc_template<threads, inst>::obj *volatile

__default_alloc_template<threads, inst>::free_list[__NFREELISTS] =

{0,0, 0, 0, 0, 0,0, 0, 0, 0, 0,0, 0, 0, 0, 0};



template<bool threads,int inst>

void* __default_alloc_template<threads, inst>::refill(size_t n)

{

    //20个节点

   int nobjs = 20;

    //申请20个节点,会修改nobjs的值,也就是申请到多少个节点

   char *chunk = chunk_alloc(n, nobjs);

    obj *volatile * my_free_list;

    obj *result;

    obj *current_obj, *next_obj;

   int i;

    

    //如果只申请到一个节点,直接返回

   if(1 == nobjs)

       return (chunk);

    //找到n大小节点的位置

    my_free_list = free_list + FREELIST_INDEX(n);

    //第一个节点是用来返回的,不用存入链表中

    result = (obj*)chunk;

    //链表的第一个节点就是下一个节点

    *my_free_list = next_obj = (obj*)(chunk + n);

   for(i = 1; ; i++)

    {

        //当前节点是下一个节点

        current_obj = next_obj;

        //下一个节点是下下个节点

        next_obj = (obj*)((char*)next_obj + n);

        //如果是最后的节点了,就设置下个节点为0,并返回,否则好设置下一个节点

       if(nobjs - 1 == i)

        {

            current_obj->free_list_link =0;

           break;

        }

       else

        {

            current_obj->free_list_link = next_obj;

        }

    }

    //把申请到的第一个节点返回

   return (result);

}


template<bool threads,int inst>

char* __default_alloc_template<threads, inst>::

chunk_alloc(size_t size,int& nobjs)

{

   char *result;

    //需要的总大小(bytes)

    size_t total_bytes = size * nobjs;

    //内存池中剩余的大小

    size_t bytes_left = end_free - start_free;

    

    //如果剩余的大小大于总大小,直接返回就行了

   if(bytes_left >= total_bytes)

    {

        result = start_free;

        start_free += total_bytes;

       return (result);

    }

    //如果剩下的大小大于一个size就返回最大的内存大小

   else if(bytes_left >= size)

    {

        nobjs = bytes_left / size;

        total_bytes = size * nobjs;

        result = start_free;

        start_free += total_bytes;

       return (result);

    }

    //一个都没有

   else

    {

        //算出需要的内存大小,2倍的需求量+现有大小的1/16(需要调整)

        size_t bytes_to_get =2 * total_bytes + ROUND_UP(heap_size >> 4);

        //先把内存池中剩余的空间中的内存取出放入链表中

       if(bytes_left > 0)

        {

            obj *volatile * my_free_list =

            free_list + FREELIST_INDEX(bytes_left);

            

            ((obj*)start_free)->free_list_link = *my_free_list;

            *my_free_list = (obj*)start_free;

        }

       //申请内存

        start_free = (char*)malloc(bytes_to_get);

       if(0 == start_free)

        {

           //无法正常申请内存

           int i;

            obj *volatile * my_free_list, *p;

           //尝试拆分大节点

           for(i = size; i <= __MAX_BYTES; i += __ALIGN)

            {

                //找到比要申请的内存大一点的节点,可以把他拆分掉

                my_free_list = free_list + FREELIST_INDEX(i);

               //p等于这个链表的第一个节点

                p = *my_free_list;

               if(0 != p)

                {

                   //如果有节点,就把这个节点放入内存池中

                    *my_free_list = p->free_list_link;

                    start_free = (char*)p;

                    end_free = start_free + i;

                   return (chunk_alloc(size, nobjs));

                }

            }

            //如果找不到大的节点,只能调用第一级配置,调用客户设置的处理函数了。

            end_free =0;

            start_free = (char*)malloc_alloc::allocate(bytes_to_get);

        }

        //内存池大小调整

        heap_size += bytes_to_get;

        end_free = start_free + bytes_to_get;

       return (chunk_alloc(size, nobjs));

    }

}







0 0
原创粉丝点击