第五章节 other issues
文章目录
- 第五章节 other issues
- GNU4.9分配器
- 1.new_allocator和malloc_allocator(最简单的)
- 2.智能型的分配器
- 1.array_allocator
- 2.debug_allocator
- 3.三种使用内存池的分配器
- 1.__pool_allocator
- 2.__mt_allocator
- 3.bitmap_allocator
- 1.内存分配
- 2.内存回收
- 4.这些分配器的使用
就是介绍一下GUN的其他分配器,方便在各种情形下去使用
GNU4.9分配器
分配器各有各的优势。
1.new_allocator和malloc_allocator(最简单的)
new_allocator
实现出简单的operator new和operator delete,这个好处就是能够重载。
malloc_allocator
直接调用malloc和free,没有经过operator new / delete,所以没有重载的机会。
2.智能型的分配器
array_allocator、debug_allocator、__mt_allocator、__pool_allocator、bitmap_allocator都是智能型
1.array_allocator
允许分配一个已知且固定大小(known and fixed size)的内存块,这些内存来自std::array
对象。使用这个分配器,大小固定的容器(包括std::string
)就不再需要调用operator new
和operator delete
。这就使我们能够使用STL abstractions,而无需在运行时造成混乱或增加开销。甚至在程序启动时也可以使用这种分配器。
其实就是用C++底部的静态的数组来供应内存,然后如果一开始就知道大小的话,这个就比较好用,速度也快。既不是new也不是malloc。
array_allocator的使用
arrat_allocator并不会回收已经给出的内存空间。(不能回收其实没有啥用)
静态分配,不需要free。没啥用,因为不free,用过的空间不能再次使用了。
也可以将底部C++的数组换成标准库的array容器。
2.debug_allocator
这是一个包装器(wrapper),可以包装在任何分配器(allocator)之上。它会将用户的请求量增加一些,然后由分配器进行响应,并使用那一小块额外的内存来存储大小信息。一旦deallocate()
函数接收到一个指针,它就会检查大小信息,并使用assert()
函数来确保匹配。
就是自己是加了点东西,然后分配的活一点不干都外包给它里面那个allocator。
多出来的_M_extra就是记录区块大小,就只是加了个大小,没什么用(不是我说的,是侯捷老师说的,但我也觉得没啥用)
3.三种使用内存池的分配器
下面的三种分配器实现都是内存池的思想,追求的是不要分配过多的cookie。
1.__pool_allocator
就是GNU2.9中的alloc,这里不再赘述。
2.__mt_allocator
多线程的内存分配器。
3.bitmap_allocator
是个bitmap index,用以索引至一个以2的指数倍成长的篮子
一个高效能的分配器,使用bit-map追踪被使用和未被使用的内存块。
1.内存分配
关于blocks,supper-blocks,bitmap,mini-vector
1.上图是一个super block
bitmap用于存放后面的block是否被分配出去
use-count表示已经分配了多少个
2.__mini_vector是控制中心,用来管理后面的block,指向block的头尾
bitmap的变化方向和_M_start变化方向相反
start和finish是super block的空闲块的头和尾,end_of_storage指的是容量的尾巴(就那个会扩容两倍那个实际上的容量的尾巴,模仿标准库vector容器写的)
3.如果一个super block用光了,就会新起一个super block,控制中心mini_vector也会增长,而且能够分配的内存会翻倍,如下图:
用1表示还没分配的block,用0表示已经分配的block,前面的数字会标识还有几块空闲没有被分配的
4.这个vector的entries无限制,每个entry代表一种value type,不用的value type即使大小相同也不混用
就和一个类有一个分配器一样的,这里的entry代表的super block也是每个类型一个,不会混用
2.内存回收
如果发生全回收,便会造成下一次分配的内存规模减半(它自己设计就是这样的,不用纠结)。图中64,128,256全部都回收,那下一次malloc分配的话就是给分配128个blocks。
下面是第一个64blocks的全回收
全回收,使用另外一个__min_vector来登记(free list)全回收的super block。对于原来的两个指针,是用vector的erase来删除的,就相当于删掉了vector的0,1号元素。
问题1的答案其实是0号和2号都可以的。但是测出来是2号,这个是无所谓的。
问题2的答案是唯一的。因为要先用已经分配过得内存,这一点是好的。
发生全回收,则分配内存减半,如下图是三次全回收
的情况:
右上角的_s_free_list就是登记全回收的super block的链表,释放的时候就看这里面哪个super block最长最大,就释放掉谁。
如果free list中已经有64个super block,下一次再free的的super block,直接delete。
如果要这时候要申请一个block,那就从_s_free_list里面恢复一个进行使用