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




//---------------------------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>

inline void construct(T1* p, const T2& value)

{

    new (p) T1(value);

}


template<class T>

inline void destroy(T* pointer)

{

    pointer->~T();

}


template<class ForwardIterator>

inline void destroy(ForwardIterator first, ForwardIterator last)

{

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

}


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

}


template<class ForwardIterator>

inline void

__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)

{

    for(; first < last; ++first)

        destroy(&*first);

}


template<class ForwardIterator>

inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}


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

    }

}







posted @ 2015-04-06 11:04  boydfd  阅读(266)  评论(0编辑  收藏  举报