一个 C++所写的 易于学习的 内存池
在 C++ 中 无论你选择怎么样动态分配内存 你最后 都会通过 着每一条路径 走到 malloc/free 函数
new -> operator new -> malloc
而 频繁调用 malloc 有两个缺点 一个是 多了一次 函数调用的开销
另一个是 malloc 分配出来的内存块 会多分配一些内存 来记录这块内存块的 元信息 俗称 cookie
当你 频繁调用 malloc 小内存块的时候 这一部分元信息 就显得非常庞大 因此 内存池 主要是 减少 cookie 同时 减少 malloc 函数的调用
内存池 主要是在 operator new 函数重载中 做一些操作
首先维护 16条自由链表 free_list[16]
掌控着16种不同小内存的分配 如果 超出了这16种小内存即 超过128字节的时候 则 交给 malloc()
去分配
16种小内存 分别为 8的倍数 如果小于8的倍数 会将其调整为 8 的倍数的边界
当 外界使用 std::alloc
分配内存时 每次 std::alloc
会获取 20 * 2
个 size 那么大的大内存块 其中 一份 20
进行切割为一个单向链表 剩下一份 20
会保留下来 以便下次使用
比如 我向 std::alloc 分配 32 字节的内存
此时 std::alloc 会去获取 20 * 2 个 32个字节 + RoundUp(目前已申请的量 >> 4)追加量 那么大的内存块
其中 20 个 32个字节 会切割成单向链表 然后返回头一块回去
剩下的 20个 会保留起来 不做切割 假如未来我向 std::alloc 要 64个字节的内存的时候 就会从 保留的20个32个字节那么大的内存块里面切割
相当于切成了 10份 也是一样 返回头一块
换句话说 就是 如果没有预备内存的话 就会去申请 每次申请 20 * 2 * size + [RoundUp(目前已申请的量 >> 4)] 追加量
那么大的内存块 下次申请 如果有预备内存就直接用保留下来的那一份 如果没有了 则再次按照一开始的设定去申请一整块大内存
RoundUp()
函数内部是将其调整为 8
的字节
此外 就算预备内存足够大 也不会切超出 1~20块内存 永远在 20 以内