分配器allocator
分配器是为容器分配内存的,效率相当重要
-
空间利用率
-
速度
最重要的两个函数,内存的申请与回收
- allocator
- deallocator
1. Operator new() 和 malloc()
operator new() 会调用 malloc();
malloc分配的内存布局
- 0x41 cookie
- pad 表示填充
- debug mode会有固定的调试信息内容
- 具体的内容在c++内存管理中提到
VC6 STL 对allocator 的使用
vc的分配器调用 operator new -> malloc
vc的分配器调用 operator delete -> free
- Vc6 的allocator调用的是operator new 和 operator delete ,没有特殊的设计
不鼓励直接使用分配器,但是可以帮助了解源代码
// 分配512个int
int* p = allocator<int>().allocate(512, (int*) 0); // 临时对象,没有名称
// 由第二个参数告诉分配器传入的是什么类型
// 归还给操作系统
allocator<int>(). deallocate(p, 512); // 不仅要告诉指针,还要告诉当初分配的元素个数
BC5 STL 对allocator 的使用
allocator 的实现
- 也是没有任何特殊的设计
- 如果容器放置了大量的元素,每个元素的size都很小,操作带来的额外的开销就会很大。
- 提供了一个默认值,调用时可以少写一个参数
GNUC 实现的allocator
allocate调用的是全局的::allocate ,调用的也是operator new() -> malloc
deallocate调用的是全局的::deallocate, 调用的是operator delete() -> free
GNU (之前的版本SGI) STL 使用的是另一种allocator。实际上GNUC 用的是SGI的分配器 alloc
GNUC所使用的分配器alloc
主要的诉求是减少malloc的次数,malloc会带有overhead(内存布局)额外的开销,overhead中最重要的就是上下两个cookie,记录了分配的内存容量(16的整数倍),free通过这个cookie来知道要回收内存的容量。
0 - 15 个链表负责 8byte - 128 byte 容量的,比如申请50个字节,会调整到56,由链表#7负责管理。
如果放100万元素,如果都不带cookie,会节省800 万 - 8字节的空间 cookie的数量会少很多。
- 这种方式有一个很小的缺陷。
gnuc 4.9 allocator
- 基类是 new_allocator
- 内存分配和释放的动作没有特殊的设计
- why? 没人知道hhh
- alloc还在,__pool_alloc 就是2.9的alloc
仍然可以使用,注意命名空间
vector<string, __gnu_cxx::__pool_alloc<string>> vec;
结论
三个厂商的STL 分配器
- 如果元素的size很小,那么操作带来的额外开销占比例就会很大
- 如果元素的size大,那么操作带来的额外开销就没有那么大,可以让使用者接受,这可能就是要自己设计分配器的原因
- 在现实中,元素的size都很小