SGI STL內存管理

在SGI STL版本的內存管理中,使用這樣一種方式來分配內存:內存分配+對象初始化。首先是分配內存,其次是根據對象的類型(是否爲POD【Plain of Data】)來使用最有效的方式來初始化對象。回收內存也是用一樣的方式:析構對象+回收內存,根據對象是否爲POD類型,肯定最有效的析構方式。
SGI STL使用雙層級配置器,第一級配置器直接使用malloc()和free(),第二級根據以下策略:當配置區塊>128 Bytes時,視之爲「足夠大」,調用一級配置器,不然視之爲太小,調用二級配置器。dom

一級配置器:__malloc_alloc_template

template <int __inst>        //非型別參數,沒排上用處
class __malloc_alloc_template 
{
    private:
        static void* _S_oom_malloc(size_t);        //用來處理內存不足的狀況,out of memory
        static void* _S_oom_realloc(void*, size_t);
        static void (* __malloc_alloc_oom_handler)();

    public:
        static void* allocate(size_t __n)    //分配內存
        {
            void* __result = malloc(__n);
            if (0 == __result) 
                __result = _S_oom_malloc(__n);
            return __result;
        }

        static void deallocate(void* __p, size_t )        //釋放內存
        {free(__p);}

        static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)        //在原有的基礎上再次分配內存
        {
            void* __result = realloc(__p, __new_sz);
            if(0 == __result) 
                __result = _S_oom_realloc(__p, __new_sz);
            return __result;
        }

        static void (* __set_malloc_handler(void (*__f)()))()        //指定本身的oom handler
        {
            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;        //默認沒有oom處理

template <int __inst>
void* __malloc_alloc_template<__inst>::_S_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_template<__inst>::_S_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);
    }
}

二級配置器:__default_alloc_template

template <bool threads, int inst>
class __default_alloc_template 
{
    private:
        enum {_ALIGN = 8};        //每一個小內存塊的大小相差爲8
        enum {_MAX_BYTES = 128};        //最大的小內存的大小爲128bytes
        enum {_NFREELISTS = 16};         //小內存塊的類型
        
        static size_t _S_round_up(size_t __bytes)        //將須要的小內存塊大小上調爲8的倍數
        { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }    //(x+7)& ~7

        union _Obj         //在區塊中保存的對象類型,爲了節省內存,使用這種方式
        {
            union _Obj* _M_free_list_link;
            char _M_client_data[1];    
        };
        
    private:
        static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS];         //存儲對象鏈表
        
        static  size_t _S_freelist_index(size_t __bytes)     //根據須要分配的對象,獲取區塊索引
        {return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);}

        static void* _S_refill(size_t __n);
        static char* _S_chunk_alloc(size_t __size, int& __nobjs);

        static char* _S_start_free;        //起始,結束
        static char* _S_end_free;
        static size_t _S_heap_size;

    public:
        static void* allocate(size_t __n)        //獲取內存塊
        {
            void* __ret = 0;

            if (__n > (size_t) _MAX_BYTES)         //若是須要的內存塊大小>128,調用一級配置器進行分配
                return __ret = malloc_alloc::allocate(__n);

            _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n);    //獲取須要的free_list
            _Obj* __RESTRICT __result = *__my_free_list;        //從鏈表頭部獲取一塊小內存
            
            if (__result == 0)    //若是沒有找到可用的free_list,準備從新填充free list
            {
                __ret = _S_refill(_S_round_up(__n));
                return __ret;
            } 

            *__my_free_list = __result -> _M_free_list_link;    //調整free_list的頭部指向下一個

            return __result;
        };

        static void deallocate(void* __p, size_t __n)    //釋放一塊小的區塊至free_list
        {
            if (__n > (size_t) _MAX_BYTES)    //若是想要歸還的區塊>128,調用一級配置器
                malloc_alloc::deallocate(__p, __n);
            else 
            {
                _Obj* __STL_VOLATILE*  __my_free_list = _S_free_list + _S_freelist_index(__n);        //找到合適的free_list
                _Obj* __q = (_Obj*)__p;        //臨時存儲即將歸還的小區快

                __q -> _M_free_list_link = *__my_free_list;    //將這個歸還的小區塊置爲free_list的頭部
                *__my_free_list = __q;        //調整區塊列表的頭部指針
            }
        }

        static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz);
} ;


template <bool __threads, int __inst>
void* __default_alloc_template<__threads, __inst>::_S_refill(size_t __n)        //爲內存不足的free_list從新填充空間
{
    int __nobjs = 20;
    char* __chunk = _S_chunk_alloc(__n, __nobjs);        //嘗試調用chunk_alloc獲取20個新的區塊做爲free_list的新節點
    _Obj* __STL_VOLATILE* __my_free_list;
    _Obj* __result;
    _Obj* __current_obj;
    _Obj* __next_obj;
    int __i;

    if (1 == __nobjs)     //若是獲取的區塊數量爲1,這塊能夠直接返回,等下次內存不足時在作處理
        return(__chunk);
    __my_free_list = _S_free_list + _S_freelist_index(__n);    //在鏈表中獲取合適的free_list

    __result = (_Obj*)__chunk;        //從剛剛獲取的20個區塊中,先拿走一個,做爲返回的結果
    *__my_free_list = __next_obj = (_Obj*)(__chunk + __n);        //將第二個區塊做爲頭部,而後經過循環,將這些區塊添加到free_list中
    for (__i = 1; ; __i++) 
    {
        __current_obj = __next_obj;
        __next_obj = (_Obj*)((char*)__next_obj + __n);
        if (__nobjs - 1 == __i) 
        {
            __current_obj -> _M_free_list_link = 0;
            break;
        } 
        else 
        {
            __current_obj -> _M_free_list_link = __next_obj;
        }
    }
    return(__result);
}

template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, int& __nobjs)        //從內存池中獲取足夠的內存給free_list使用
{
    char* __result;
    size_t __total_bytes = __size * __nobjs;        //要獲取的總的內存數量
    size_t __bytes_left = _S_end_free - _S_start_free;        //內存池中的剩餘空間

    if (__bytes_left >= __total_bytes)         //若是剩餘空間足夠的話
    {
        __result = _S_start_free;        
        _S_start_free += __total_bytes;
        return(__result);
    } 
    else if (__bytes_left >= __size)         //若是剩餘的空間不足以知足全部的需求,可是足夠供應一個以上的區塊
    {
        __nobjs = (int)(__bytes_left/__size);        
        __total_bytes = __size * __nobjs;        
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } 
    else         //內存池提供的內存連一個以上的內存塊都沒法供應
    {
        size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size >> 4);        //若是須要從新分配內存,這是須要從新分配內存的數量
        if (__bytes_left > 0)         //若是內存池中還有零頭,將零頭加入free_list中
        {
            _Obj* __STL_VOLATILE* __my_free_list =
                        _S_free_list + _S_freelist_index(__bytes_left);        

            ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
            *__my_free_list = (_Obj*)_S_start_free;
        }
        _S_start_free = (char*)malloc(__bytes_to_get);    //配置heap空間,用來補充內存池
        if (0 == _S_start_free)          //若是從堆中獲取內存失敗,咱們將採用以下策略:檢驗咱們手上空閒的,較大的內存塊,將這個較大的內存塊歸還到堆中,而後就能夠從新進行配置了      
        {
            size_t __i;
            _Obj* __STL_VOLATILE* __my_free_list;
        _Obj* __p;
            
            for (__i = __size;__i <= (size_t) _MAX_BYTES;__i += (size_t) _ALIGN) 
            {
                __my_free_list = _S_free_list + _S_freelist_index(__i);    //獲取當前的free_list
                __p = *__my_free_list;        //若是這個free_list的head存在
                if (0 != __p) {
                    *__my_free_list = __p -> _M_free_list_link;
                    _S_start_free = (char*)__p;        //將這個頭部的free_list歸還到堆中去,調整堆指針的位置
                    _S_end_free = _S_start_free + __i;
                    return(_S_chunk_alloc(__size, __nobjs));        //不用擔憂有剩餘,任何殘餘的零頭都會被編入合適的free_list中去
                }
            }
            
            _S_end_free = 0;    // 通常狀況下,不會執行到這一塊。若是出現意外,會調用一級配置器的異常處理機制獲取內存
            _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
        }
        _S_heap_size += __bytes_to_get;        //通常不會執行到這一塊
        _S_end_free = _S_start_free + __bytes_to_get;
        return(_S_chunk_alloc(__size, __nobjs));
    }
}

template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_start_free = 0;

template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_end_free = 0;

template <bool __threads, int __inst>
size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0;

template <bool __threads, int __inst>
typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE
__default_alloc_template<__threads, __inst> ::_S_free_list[
# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)
    _NFREELISTS
# else
    __default_alloc_template<__threads, __inst>::_NFREELISTS
# endif
] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

標準配置器:simple_alloc

template<class _Tp, class _Alloc>
class simple_alloc 
{
    public:
        static _Tp* allocate(size_t __n)
        { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); }
        
        static _Tp* allocate(void)
        { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); }
    
        static void deallocate(_Tp* __p, size_t __n)
        { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); }
    
        static void deallocate(_Tp* __p)
        { _Alloc::deallocate(__p, sizeof (_Tp)); }
};

基本的內存配置工具

其中最影響效率的因素在於判斷是Value否爲POD類型,根據是否爲POD類型作出不一樣的處理。工具

uninitialized_copy

template <class _InputIter, class _ForwardIter>
inline _ForwardIter uninitialized_copy(_InputIter __first, _InputIter __last, _ForwardIter __result)
{
    return __uninitialized_copy(__first, __last, __result, __VALUE_TYPE(__result));        //萃取出__result的類型,判斷是否爲POD類型
}

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

template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter __uninitialized_copy(_InputIter __first, _InputIter __last,_ForwardIter __result, _Tp*)
{
    typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;        //萃取_Tp的類型
    return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());        //利用重載的方式在編譯期選擇處理
}

template <class _InputIter, class _ForwardIter>
inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result, __true_type)
{
    return copy(__first, __last, __result);        //若是是POD類型,直接進行memcpy進行處理就行
}

template <class _InputIter, class _ForwardIter>
_ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result,__false_type)
{
    _ForwardIter __cur = __result;        //若是非POD類型,逐個在_result類型上進行construct
    __STL_TRY 
    {
        for ( ; __first != __last; ++__first, ++__cur)
            _Construct(&*__cur, *__first);
        return __cur;
    }
    __STL_UNWIND(_Destroy(__result, __cur));
}

uninitialized_copy_n

template <class _InputIter, class _Size, class _ForwardIter>
inline pair<_InputIter, _ForwardIter> uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result) 
{
    return __uninitialized_copy_n(__first, __count, __result,__ITERATOR_CATEGORY(__first));        
}

template <class _InputIter, class _Size, class _ForwardIter>
inline pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result) 
{
    return __uninitialized_copy_n(__first, __count, __result,__ITERATOR_CATEGORY(__first));
}

template <class _RandomAccessIter, class _Size, class _ForwardIter>
inline pair<_RandomAccessIter, _ForwardIter> __uninitialized_copy_n(_RandomAccessIter __first, _Size __count,_ForwardIter __result,random_access_iterator_tag) 
{
     _RandomAccessIter __last = __first + __count;
    return pair<_RandomAccessIter, _ForwardIter>(__last,uninitialized_copy(__first, __last, __result));
}

template <class _InputIter, class _Size, class _ForwardIter>
pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result,input_iterator_tag)
{
    _ForwardIter __cur = __result;
    __STL_TRY 
    {
        for ( ; __count > 0 ; --__count, ++__first, ++__cur) 
            _Construct(&*__cur, *__first);
        return pair<_InputIter, _ForwardIter>(__first, __cur);
    }
    __STL_UNWIND(_Destroy(__result, __cur));
}

uninitialized_fill

template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,_ForwardIter __last, const _Tp& __x)
{
    __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first));
}

template <class _ForwardIter, class _Tp, class _Tp1>
inline void __uninitialized_fill(_ForwardIter __first,_ForwardIter __last, const _Tp& __x, _Tp1*)
{
    typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;
    __uninitialized_fill_aux(__first, __last, __x, _Is_POD());               
}

template <class _ForwardIter, class _Tp>
void __uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,const _Tp& __x, __false_type)
{
    _ForwardIter __cur = __first;
    __STL_TRY 
    {
        for ( ; __cur != __last; ++__cur)
            _Construct(&*__cur, __x);
    }
    __STL_UNWIND(_Destroy(__first, __cur));
}

template <class _ForwardIter, class _Tp>
inline void __uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,const _Tp& __x, __true_type)
{
    fill(__first, __last, __x);
}

uninitialized_fill_n

template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x)
{
    return __uninitialized_fill_n(__first, __n, __x, __VALUE_TYPE(__first));
}

template <class _ForwardIter, class _Size, class _Tp, class _Tp1>
inline _ForwardIter __uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*)
{
    typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;
    return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());
}

template <class _ForwardIter, class _Size, class _Tp>
_ForwardIter __uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,const _Tp& __x, __false_type)
{
    _ForwardIter __cur = __first;
    __STL_TRY 
    {
        for ( ; __n > 0; --__n, ++__cur)
            _Construct(&*__cur, __x);
        return __cur;
    }
    __STL_UNWIND(_Destroy(__first, __cur));
}

template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter __uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,const _Tp& __x, __true_type)
{
    return fill_n(__first, __n, __x);
}
相關文章
相關標籤/搜索