前不久谷歌表示,使用 TCMalloc 可以代替 C 和 C++ 默认内存分配器,以提供更加高效的扩展效率和更加良好的并行性支持。
为了避免误解,这里值得注意的是,这次实际上已经是谷歌第二次开源其内存分配器。早在2005年,谷歌就向所有人提供了其内存分配器。谷歌当时将其作为性能工具的一部分连同其他工具一起推出的,这些工具包括确保堆一致性的堆检查器以及基于 Perl 的 ppro 配置分析器和可视化工具。
然而随着时间推移,谷歌使用的内部版本与外部版本出现了较大的差异,因此此次谷歌开源的 TCMalloc 版本,其中就包括一些改进,如每个 CPU 缓存、一定规模大小的删除、快 / 慢路径改进,等等。
我们在生产中的所有 C++ 程序都在使用TCMalloc。该代码仅限于C++的内存分配器实现本身。
如之前所述,TCMalloc 包含 C*alloc 族和针对 C++ 的::operator new 以及::operator delete 的实现。与C 和 C++ 标准库提供的相应功能比较,TCMalloc提供了大量优化。如TCMalloc能利用固定大小的“页”从操作系统中执行分配任务,从而大大简化了簿记过程。而且其中一些页面专门用于特定大小的对象,例如所有 16 字节的对象。在需要获取或释放内存的时候,这些操作带来了简化。最后,它还能缓存常用对象以提高操作速度。
通过 MallocExtension,TCMalloc 还支持遥测扩展,这样对于收集堆探查结果和快照以调查内存行为很有用。
此外还有一些配置选项可以用来调试 TCMalloc性能。特别是我们可以自己定义逻辑页面大小,它们可以是 4KiB、8KiB、32KiB 或 256KiB。越大的页面将减少从操作系统重新请求新页面分配的可能性,从而以消耗更多的内存来实现更快的操作。而且它还可以基于每个线程或者每个CPU来设置缓存大小,这也是默认设置。最后我们还能调整内存释放的积极程度,这也会在几个方面影响性能。
TCMalloc 架构如下图所示,在相关文档中有详细的描述:
最后TCMalloc 只能使用谷歌的内部构建系统 Bazel 来实现构建,这对于一些使用其他构建系统的人来说,有点让人感觉意外。但是对 macOS、Ubuntu、Fedora 和 Windows 来说都有二进制格式的 Bazel 可用,因此,这可能不会成为主要障碍。