2.SGI STL第二级空间配置器__default_alloc_template的chunk_alloc函数

SGISTL默认使用二级空间配置器,当需要配置的区块大于128 bytes时SGI STL调用一级空间配置器,一级空间配置器的allocate函数直接使用malloc分配内存,deallocate函数直接使用free释放内存。当需要配置的区块小于128 bytes时SGI STL调用二级空间配置器。

相比于一级空间配置器简单粗暴的内存使用方法,二级空间配置器对内存的使用显得精细很多。

二级空间配置器的具体用法请看书,我就不抄书了,只对二级空间配置器中容易糊涂的地方写一下我的理解。

内存池和free_list到底什么关系?

二级空间配置器维护了一个内存池,有一个名为free_list的数组负责管理内存池。free_list的每个元素构成一个链表,同一个链表的每个元素指向的内存大小相同,free_list的所有链表节点指向的内存大小 <= 内存池。

之所以使用数组而不是链表,我猜测有两个原因:1. 二级空间配置器把内存池分为固定的16个大小等级,即free_list的长度(16)是固定的;2.既然free_list的长度固定那么采用数组无疑是时间效率更高的方法(O(1)),如果采用链表,free_list的查询效率为O(n)。

一下是我理解的二级空间配置器执行过程,时间关系,不画程序流程图了。

1.             二级空间配置器在索要内存时调用allocate函数,如果索要的内存大于128字节,调用一级空间配置器,否则allocate查free_list数组,从free_list中某个元素指向的链表中取出一块内存后返回。

2.             当free_list没有合适的内存区块时调用refill函数。

3.             refill调用_S_chunk_alloc,_S_chunk_alloc分配一段内存给内存池,把内存池残余的空间编入free_list。

4.             _S_chunk_alloc 调用完毕,回到refill,refill查free_list数组,从free_list中某个元素指向的链表中取出一块内存后返回给allocate,allocate再返回给客户端。

_S_chunk_alloc函数的源码:

template <bool __threads, int __inst>
char*
__default_alloc_template<__threads,__inst>::_S_chunk_alloc(size_t __size,
                                                            int&__nobjs)
{
    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);
        //Try to make use of the left-over piece.
        //把内存池当前剩下的一些小残余零头利用一下。
        if (__bytes_left > 0) {
            _Obj*__STL_VOLATILE* __my_free_list =
                        _S_free_list+ _S_freelist_index(__bytes_left); // 这里对吗?假如__bytes_left =15,则_S_freelist_index(15) = 1,
                                                                        //即16B的位置,而实际上只剩下了15B?

            ((_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);
        if (0 == _S_start_free) {
            size_t __i;
            _Obj*__STL_VOLATILE* __my_free_list;
        _Obj*__p;
            //Try to make do with what we have.  That can't
            //hurt.  We do not try smaller requests, since that tends
            //to result in disaster on multi-process machines.
            for (__i = __size;
                 __i<= (size_t) _MAX_BYTES;
                 __i+= (size_t) _ALIGN) {
                __my_free_list= _S_free_list + _S_freelist_index(__i);
                __p= *__my_free_list;
                if (0 != __p) {
                    *__my_free_list= __p -> _M_free_list_link;
                    _S_start_free= (char*)__p;
                    _S_end_free= _S_start_free + __i; // 这里确定每一块内存大小都是__i吗?
                    return(_S_chunk_alloc(__size,__nobjs));
                    //Any leftover piece will eventually make it to the
                    //right free list.
                }
            }
        _S_end_free= 0;    // In case of exception.
            _S_start_free= (char*)malloc_alloc::allocate(__bytes_to_get);
            //This should either throw an
            //exception or remedy the situation.  Thus we assume it
            //succeeded.
        }
        _S_heap_size+= __bytes_to_get;
        _S_end_free= _S_start_free + __bytes_to_get;
        return(_S_chunk_alloc(__size,__nobjs));
    }
}

可以看到chunk_alloc函数的输入有两个:1. int&__nobjs,待分配的元素个数;2. size_t __size,每个元素的大小。

chunk_alloc函数的程序流程图(为了方便观察,画的并不是标准的程序流程图)如下:

时间: 2024-10-05 02:42:11

2.SGI STL第二级空间配置器__default_alloc_template的chunk_alloc函数的相关文章

SGI STL第二级空间配置器空间释放函数deallocate

union obj{ obj * free_list_link ; char client_data[1] ; }; __default_alloc_template拥有配置器标准接口函数deallocate().该函数首先判断区块大小,大于128bytes就调用第一级配置器,小于128bytes就找出相应的free list将区块回收: <span style="font-size:18px;">//p is not 0/null static void dealloca

STL源码分析--第二级空间配置器

本文讲解SGI STL空间配置器的第二级配置器. 相比第一级配置器,第二级配置器多了一些机制,避免小额区块造成内存的碎片.不仅仅是碎片的问题,配置时的额外负担也是一个大问题.因为区块越小,额外负担所占的比例就越大. 额外负担是指动态分配内存块的时候,位于其头部的额外信息,包括记录内存块大小的信息以及内存保护区(判断是否越界).要想了解详细信息,请参考MSVC或者其他malloc实现. SGI STL第二级配置器具体实现思想 如下: 如果要分配的区块大于128bytes,则移交给第一级配置器处理.

STL:二级空间配置器浅谈

我们在编写程序过程中,需要内存时,我们第一反应就是malloc,但是这样容易产生内片无法被利用. 在STL中提到了空间适配器,它主要分为两级:一级空间适配置器,二级空间配置器.一级空间适配器是对malloc的简单包装,它内部的allocate()和reallocate()都是在调用malloc()和realloc()不成功后,再调用oom_malloc()和oom_realloc()[清理内存],重复多次后,如果还不成功便调用_THROW_BAD_ALLOC,丢出bad_alloc异常信息. 二

C++ STL学习之 空间配置器(allocator)

标签(空格分隔): C++ STL 众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间)分配的工具,他与容器联系紧密,每一种容器的空间分配都是通过空间分配器alloctor实现的.理解alloctor的实现原理,对内存结构以及数据存储形式会有更清晰直观的认识. 1.两种C++类对象实例化方式的异同 在c++中,创建类对象一般分为两种方式:一种是直接

STL初探——第二级配置器 __default_alloc_template的学习心得

SGI STL 第二级配置器使用的是memory pool,即内存池,相比较于第一级空间配置器,第二级空间配置器多了许多限制,主要是为了防止申请小额区块过多而造成内存碎片.当然小额区块在配置时实际上是对空间配置器效率的一种伤害.另外,索求任何一块内存,都得需要一些额外内存来进行标记,虽然这些标记占内存很小很小,但蚂蚁多咬死象,小区块多了,这些小标记还是挺浪费内存的,但这也无法避免,毕竟系统需要靠这些小标记管理内存. SGI 第二级配置器的做法是,如果区块足够大,超过128bytes时,就移交第一

SGI版本空间配置器

1.STL中的空间配置器 在STL中,空间配置器分了2组,分别为一级空间配置器和二级空间配置器,但是它们都有自己各自运用的场合:一般说来,一级空间配置器一般分配的空间大于128B,二级空间配置器的分配空间为小于128B. 其中SGI 中的STL的空间配置器设计哲学如下: (1).向system heap要求申请空间 (2).考虑多线程的状态 (3).考虑内存不足时的应变措施 (4).考虑过多"小型区块"可能造成的内存碎片问题 在剖析源码时,为了将问题控制在一定的复杂度内,以下源码皆排除

STL学习笔记--2、空间配置器 allocator

2.1标准接口 allocator::value_type allocator::pointer allocator::const_pointer allocator::reference allocator::const_reference allocator::size_type allocator::difference_type allocator::rebind allocator::allocator()//默认构造函数 allocator::allocator(const allo

【STL】空间配置器剖析(二)

上篇文章点击打开链接主要对于对象的构造含和析构进行了主要说明,这篇文章将对对象构造前的内存配置和对象析构后的空间释放进行深入探索. 好的,话不多说马上进入是正文: 对对象构造前的内存配置和对象析构后的空间释放,由<stl_alloc.h>负责,SGI对此的设计哲学如下: 向system heap要求空间. 考虑多线程的状态 考虑内存不足的应变措施 考虑过多的"小型区块"可能造成的内存碎片问题 C++的内存配置的基本操作是:operator new(),内存释放的基本操作是o

stl空间配置器alloc

SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(),第二级配置器视情况采用不同的策略:当配置区块超过128bytes时,调用第一级配置器,当配置区块小于128bytes时,采用内存池方式 //SGI第一级配置器 template<int inst> class __malloc_alloc_template { private: //处理内存不足的情况 //c++ new handler机制:系统在内存配置需求无法被满足时,调用一个指定函数,参见effective c