首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

SGI STL空间配置器跟内存池

2012-08-11 
SGI STL空间配置器和内存池最近在看侯捷老师的《STL源码剖析》,非常感叹其中空间配置器实现的巧妙和细致,对

SGI STL空间配置器和内存池
最近在看侯捷老师的《STL源码剖析》,非常感叹其中空间配置器实现的巧妙和细致,对效率真正是锱铢必较。

  一般我们所习惯的内存配置和释放是通过new和delete来完成的,而new运算包含了两个阶段:1.调用::operator new配置内存 2.调用构造函数 Foo() 构造对象。delete运算也包含两个阶段:1.调用析构函数 ~Foo() 将对象析构 2.调用::operator delete释放内存。

1 #if 02 #  include <new>3 #  define __THROW_BAD_ALLOC throw bad_alloc4 #elif !define( __THROW_BAD_ALLOC)5 #  include <iostream.h>6 #define  __THROW_BAD_ALLOC cerr<<" out of memory "<<endl;exit(1)7 #endif

  然后我们看二级配置器,它是以内存池 ( memory pool ) 来管理的:它由16个自由链表构成,每次配置一大块内存,并维护对应之自由链表 ( free-lists ),下次若有相同大小的内存请求,就直接从free-lists 中拨出这块内存,同时,如果客端释放小额区块时,刚把它回收到对应大小的自由链表 ( free-lists )中。

  这16个肩负重任的 free-lists 分别管理大小为 8,16,24,32,40,56,64,72,80,88,96,104,112,120,128 bytes 大小的小额区块,所以当申请小额内存时,内存的需求量会被上调至 8 的倍数,以便于管理。接下来内存池就要登场了……

  首先由空间配置函数 allocate() 进行空间的配置,如果能够在 free-lists 中找到对应大小的区块,就把对应的区块拨出,返回。否则就要调用 refill() 对 free-lists 进行填充,新的空间来自内存池,由 chunk_alloc() 完成。缺省是取得20个新区块,但如果内存池空间不足数量会小于20。取得的新区块,把第一块 return ,剩余的则维护到free-list中。

  我们看下 chunk_alloc() 是怎么工作的:

  从内存池是取出新空间可能发生三种情况

  1. 内存池剩余量完全满足需求量

  2. 内存池剩余量不能完全满足需求量,但足够供应  >= 1 个 区块

  3. 内存池剩余量一个区块都不能供应

 1  chunk_alloc(size, nobjs) 2  { 3      …… 4    5      if(bytes_left >= total_bytes)  // 1.剩余量大于需求量 6      {……} 7      else if(bytes_left >= size)      //2.能供应至少一个区块 8      {……} 9      else{10      ……       //3.一个都不能供应11      }12  }

     首先我们看第一种情况:内存池剩余量完全满足需求量

  这种情况是最好的情况,直接返回所需的区块就可以了

  第二种情况: 内存池剩余量不能完全满足需求量,但足够供应  >= 1 个 区块

  这种情况也好办,我们只要计算出实际能够供应的区块的个数,然后返回这些区块就可以了

  剩下最后一种情况:内存池剩余量一个区块都不能供应

  这种情况比较麻烦了,我们首先要进行 “善后” , 把剩余的这些残余的空间回收到 free-lists 中,然后才申请分配新的空间。申请新空间的大小为所需空间的2倍,再加上一个随着配置次数增加而增加的附加量。内存池向堆空间索要内存,用malloc(), 如果成功,则调整内存池的起点和终点,递归调用 chunk_alloc() 就行了,否则如果分配内存失败,就要想法从其它地方找点内存来用了,没错!就是 free-lists,向那些较大,且有剩余区块没用的free-list索要内存,如果找到了,就挖一块返回,调用chunk_alloc() 返回区块,否则就没办法了,只能调用一级配置器了,因为那里有out-of-memory处理例程,兴许还能找出点内存,如果能找到,那最好了,调用chunk_alloc()把区块返回给refill(),返回结果并调整free-lists,否则,真是天要亡我啊!只能抛出异常了……

热点排行