C/C++ 的多线程内存分配器

Posted

技术标签:

【中文标题】C/C++ 的多线程内存分配器【英文标题】:Multithreaded Memory Allocators for C/C++ 【发布时间】:2010-09-13 22:07:08 【问题描述】:

我目前有大量的多线程服务器应用程序,我正在四处寻找一个好的多线程内存分配器。

到目前为止,我很纠结:

孙梅 Google 的 tcmalloc 英特尔的线程构建块分配器 Emery Berger 的宝藏

根据我的发现,hoard 可能是最快的,但我在今天之前没有听说过它,所以我怀疑它是否真的像看起来那样好。任何人都有尝试这些分配器的亲身经历吗?

【问题讨论】:

您正在尝试使用当前使用的默认堆管理器解决哪些具体问题?还有,那是哪一个? 在您的应用程序中尝试检查是否可以通过使用线程本地存储来提高性能。如果有可能这样做,收益可能比使用多线程分配器更好。 【参考方案1】:

我使用过 tcmalloc 并阅读了有关 Hoard 的信息。两者都有类似的实现,并且都实现了相对于线程/CPU 数量的大致线性性能扩展(根据各自站点上的图表)。

所以:如果性能真的那么重要,那么就进行性能/负载测试。否则,只需掷骰子并选择列出的一个(根据目标平台上的易用性加权)。

从trshiv's link 看来,Hoard、tcmalloc 和 ptmalloc 的速度都大致相当。总体而言,tt 看起来 ptmalloc 优化为尽可能少占用空间,Hoard 优化为权衡速度 + 内存使用,而 tcmalloc 优化为纯速度。

【讨论】:

trshiv 的链接现在是here 两个链接现在都坏了【参考方案2】:

真正判断哪个内存分配器适合您的应用程序的唯一方法是尝试一些。提到的所有分配器都是由聪明的人编写的,并且将在一个特定的微基准测试或另一个上击败其他分配器。如果您的应用程序整天所做的只是在线程 A 中分配一个 8 字节块并在线程 B 中释放它,并且根本不需要处理任何其他事情,那么您可能会编写一个内存分配器来解决任何问题到目前为止列出的那些。它对其他很多事情都没有多大用处。 :)

我在工作的地方有一些使用 Hoard 的经验(足以让我发现最近的 3.8 版本中解决的一个更晦涩的错误之一是该经验的结果)。这是一个非常好的分配器——但对你来说有多好取决于你的工作量。而且你必须为 Hoard 付费(虽然它并不太贵)才能在商业项目中使用它,而无需 GPL 代码。

很长一段时间以来,经过微调的 ptmalloc2 一直是 glibc 的 malloc 背后的分配器,因此它得到了难以置信的广泛使用和测试。如果稳定性高于一切,它可能是一个不错的选择,但你没有在列表中提到它,所以我假设它已经过时了。对于某些工作负载,这很糟糕 - 但任何通用 malloc 也是如此。

如果你愿意付钱(根据我的经验,价格合理),SmartHeap SMP 也是一个不错的选择。提到的大多数其他分配器都设计为可以 LD_PRELOAD 的插入式 malloc/free new/delete 替换。 SmartHeap 也可以这样使用,但它还包括一个完整的与分配相关的 API,可让您根据自己的需要微调分配器。在我们已经完成的测试中(同样,非常特定于特定应用程序),SmartHeap 在充当 malloc 替代品时的性能与 Hoard 大致相同;两者的真正区别在于定制的程度。您需要分配器的通用性越低,您就可以获得更好的性能。

根据您的用例,通用多线程分配器可能根本不是您想要使用的;如果您不断地 malloc 和释放大小相同的对象,您可能只想编写一个简单的平板分配器。 Slab 分配用于 Linux 内核中符合该描述的多个位置。 (我会给你几个更有用的链接,但我是一个“新用户”,Stack Overflow 决定不允许新用户在一个答案中有帮助。谷歌可以提供帮助不过效果还不错。)

【讨论】:

【参考方案3】:

我个人更喜欢并推荐 ptmalloc 作为多线程分配器。 Hoard 很好,但是在几年前我的团队在 Hoard 和 ptmalloc 之间进行的评估中,ptmalloc 更好。据我所知,ptmalloc 已经存在多年,并且被广泛用作多线程分配器。

您可能会发现this comparison 很有用。

【讨论】:

链接文章已移至here。【参考方案4】:

也许这是处理您所要求的错误的方法,但也许可以完全采用不同的策略。如果您正在寻找一个非常快速的内存分配器,也许您应该问为什么您需要花费所有时间分配内存,而您也许可以摆脱变量的堆栈分配。堆栈分配虽然更烦人,但做得正确可以为您节省很多互斥争用的方式,并避免您的代码出现奇怪的内存损坏问题。此外,您可能会有更少的碎片,这可能会有所帮助。

【讨论】:

如果这是一个多线程环境,堆栈分配是只适用于少量非常小的对象的方法 - 你不想在线程上达到堆栈大小,因为那样你会得到与正常内存损坏相同的问题。 是的,我同意 hazzen。如果您处理大量数据,堆栈分配(包括线程本地存储)可能会导致内存损坏。【参考方案5】:

我们在几年前工作的项目中使用了囤积。它似乎工作得很好。我对其他分配器没有经验。尝试不同的方法并进行负载测试应该很容易,不是吗?

【讨论】:

【参考方案6】:

locklessinc 分配器非常好,如果您有问题,开发人员会及时响应。他写了一篇关于使用的一些优化技巧的文章,读起来很有趣:http://locklessinc.com/articles/allocator_tricks/。我过去用过它,效果很好。

【讨论】:

【参考方案7】:

可能对您的问题的答复较晚,但是

如果你有性能提升,为什么要使用 mallocs?

更好的方法是在初始化时执行一个大内存窗口的 malloc,然后提出一个 light weight Memory managerlease out the memory chunks at run time

如果您的堆扩展,这可以避免任何系统调用的可能性。

【讨论】:

【参考方案8】:

您可以尝试ltalloc(具有快速池分配器速度的通用全局内存分配器)。

【讨论】:

以上是关于C/C++ 的多线程内存分配器的主要内容,如果未能解决你的问题,请参考以下文章

系统C/C++内存管理之内存分配

在具有动态大小的内存池的多线程 C/C++ 中实现内存管理器?

多线程堆管理

C/C++程序内存的分配

STL的内存分配器

当试图释放堆管理器分配的内存时会发生啥,它分配的比要求的多?