zoukankan      html  css  js  c++  java
  • 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));

        }

    }







  • 相关阅读:
    读入输出优化模板
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    getElementById() 获取指定ID的第一个元素
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983147.html
Copyright © 2011-2022 走看看