第 2 章 空间配置器

总体设计

        内存空间的配置和对象的构造或析构分开。对象内容的构造/析构的任务交给两个全局函数:construct( ),destroy( )destroy( )这个根据对象的型别来判断是否需要调用其析构函数,判断的准则是对象是否具有trival destructor(如果没有在类中定义析构函数)。空间的配置由两个配置器构成,再用一个typedef声明的一个名字处理,这个名字我们称为默认空间配置器,在SGI STL采用的二级配置器。当我们声明一个容器的时候,其模板参数是有两个的,第一个为容器元素的类型,第二个就是配置器,在SGI STL里面为了使得容器的接口对 用户更加友好,还添加了一层包装,simple_alloc,这个类使得我们在容器中构造或析构对象更加方便,我们不需要指定比特大小了,这一点很想malloc/free和new/delete,我们使用malloc需要指定比特大小,而new仅仅需要指定对象多少个。在SGI STL里面还定义三个以uninitializer开头的三个全局函数,其功能是为了给未初始化的空间初始化,这三个函数都具有commit or rollback的含义,就是当我们在构造对象发生异常的时候我们要保证其原空间没有被破坏。

第一级配置器  __malloc_alloc_template

        第一级配置器是为了分配较大的空间,大于128字节,其使用malloc/free/realloc来申请/释放空间。第一级配置器具有内存分配失败处理的机制,不过需要我们手动配置处理函数。

第二级配置器  __default_alloc_template

        第二级配置器分配一些小的空间,这样做可以避免内存碎片问题,给系统造成额外负担。如果分配内存区块超过128字节就将任务转移给第一级配置器。其主要思想是以内存池管理,我们先申请一大块空间作为备用,如果需要配置空间,我们从这个内存池来取空间,当取出来的空间不需要的时候我们再还给内存池,最后再一并将内存池还给系统。在第二级配置器中一共有四个static数据成员,一个16元素的数组freelist,其每个元素都是一个链表的头结点,且其每个结点所对应的字节数分别是8-128,且为8的倍数;两个指针start_free和end_free,分别指向内存池的头部和尾端;一个偏移量heap_size,这个主要作用在往内存池添加空间的一个额外附加量,且随着添加次数越来越大。申请一个小于128字节的空间是的主要流程是:先将字节数上升为8的倍数,定位此字节数在freelist中所对应的链表,如果此时链表不为空,有空间可取,更新链表头结点;如果此时为空,我们需要从内存池中取出一定的空间添加到此链表中。从内存池取出空间具有三种情况:如果内存池空间足够我们的需要,直接返回内存池头部指针并更新头部指针;不够需要但是足够配置一个区块,此时返回最多可以配置的区块数的空间,更新头部指针;一个区块也无法提供,那么我们需要向系统申请空间注入到内存池,申请的空间是我们需要的空间的两倍再加上偏移量,首先要做的工作就是将内存池剩余空间添加到freelist适当的链表中,再申请空间注入内存池,如果申请空间失败,我们需要从freelist中其他链表(区块比我们需要的区块大的)申请一个区块注入内存池,在其他链表也没有空间时,我们就将分配空间的任务转移给第一级配置器,毕竟第一级配置器有空间分配失败的处理程序;如果申请空间成功,就申请的空间注入内存池。在上述注入内存池之后,内存池空间就已经足够我们需要的空间大小了,我们再次回到第一种情况或这第二种情况。

猜你喜欢

转载自blog.csdn.net/w1157984197/article/details/79717685
今日推荐