在 GNU 2.9 中默认的 allocator 内部是使用的 ::operator new 和 ::operator delete,并没有什么特殊操作,而它所有的容器实现,都是通过 std::alloc 实现的(作为容器初始化时的第二参数)。

而在 GNU 4.9 之后的版本,std::alloc 被移动到 ext/pool_allocator.h 中,通过 __gnu_xxx::__pool_alloc 调用

std::alloc 的内部实现

通过上图可以看到有如下特点

申请内存

在上面提到,申请内存的时候是先查看 Pool 还有没有余量,如果有,则从 Pool 中切割出一块空间挂上 free_list 的区块,free_list 的数量永远在 1 - 20之间(并不一定就是20)。

如果 Pool 没有余量,故会去申请 size * 20 * 2 + RoundUp(当前已经申请的内存大小 >> 4) 大小的内存,记为 Pool, 再从中切出一块区域(大小为size)给到返回对象,另为19个区块组成链表记录到对应的 free_list_head 中。余下的内存作为 Memory Pool 。在std::alloc 中会通过两个指针 start_free 和 end_free 指定 Memory Pool 的区域。

<aside> 💡 RoundUp 函数将内存大小调整到上界 8 的倍数

</aside>

碎片处理

有时候,当 Memory Pool 的余量还要小于下一个要创建的 free_list_head 的大小时(即小于 size),那么可以先将这一块余量大小的内存,挂在同样大小的 free_list 下。

比如说,剩余 80 bytes,但要申请的大小是 104 bytes,这时候就可以将这 80 bytes 挂在对应大小 80 bytes 的 free_list_head 的上一个。这样就完成了内存碎片处理。