STL源码剖析 第二章 空间配置器

C++内存配置操作和释放操作如下:

1 class Foo{...};
2 Foo* pf=new Foo;         //配置内存,然后构造对象
3 delete pf;               //将对象析构,然后释放内存

内存配置操作由 alloc:allocate() 负责,内存释放操作由 alloc:deallocate() 负责;对象构造操作由 ::construct() 负责,对象析构操作由 ::destroy() 负责。

destroy() 有两个版本,第一个版本接受一个指针,析构指针所指的对象。

第二个版本接受 first 和 last 两个迭代器,将 [first,last) 范围内所有对象析构。在这里我们就要考虑这些对象是否值得我们一次次的调用实际没有作用的析构函数,所以我们就利用 value_type() 求出迭代器指向对象的类型,并调用相应的 __type_traits<> 判断对象的析构函数是否是trivial的。

内存配置和释放操作复杂很多。分别第一级配置器和第二级配置器。第一级配置器的 allocate() 和 realloc() 都是在调用 malloc() 和 realloc() 不成功后,改调用 oom_malloc() 和 oom_realloc() 。后两者都有内循环,不断调用需要客端设计的“内存不足处理例程”,如果没有设计,就丢出 bad_alloc 异常信息。

 第二级配置器

union obj{
    union obj* free_list_link;    
    char client_data[1];
};

这个地方 client_data 的地址等于 obj 的地址,那么为什么我们要加上这个可有可无的代码呢?可能是用 obj->client_data 可以避免 (char*)  的强制转换吧,虽然这种方式也没有出现,说白了这行代码就没有用......

用到了一个链表数组 free_list[16] ,其中存放的区块大小分别是8、16、24... 

配置过程如下:

1.大于128Byte 由第一级配置器来

2.小于则寻找 free_list 中最合适的一种

3.进入索引后发现这种里面有,直接抽出一块

4.发现里面没有,填充 free_list

5.从内存池中抽取20*size 大小的内存,如果有,size拿出来,19*size 给free_list

6.没有,20*size,size大小有的话就将就一下

7.size都没有的话,把内存池中剩下的归到 free_list 中,因为内存池中剩余大小一定是8的倍数,所以一定有合适的 free_lists 可以匹配。完事以后 malloc 2*size+n(附加量),malloc 不成的话就去 free_list 里找高级的索引,找到就归入内存池并调用一次自己,因为此时内存池中有东西了,可以重复5-7的步骤了。高级的索引里面都没有东西的话就完蛋了,只能寄希望于第一级配置中 out-of-memory 方法,因为第一级的正常办法也是 malloc ,这条路已经行不通了。如果 out-of-memory 成了的话就归入内存池,再调用一次自己。

 

posted @ 2020-11-07 11:27  czhWellOptimized  阅读(96)  评论(0)    收藏  举报