C/C++分配器在多线程环境中的性能如何?

3

当使用new或malloc分配内存时,分配器可能需要保护自己免受重入攻击。我看到有两种方法可以做到这一点:

  • 使用一个大的互斥锁。这种解决方案很简单,但性能较差。
  • 为每个线程保留一个内存池。性能很高,但是内存池的大小可能难以评估。

我认为大多数分配器使用第二种方法,但我找不到证明。

您知道哪些分配器使用哪种方法吗?是否有任何标准规定?


今天最有能力的分配器使用两者的组合。 - Mysticial
3个回答

4

Google perf tools提供了一个名为TCMalloc的分配器。该分配器为每个线程使用一组内存池(即“线程缓存系统”)。文档显示相对于glibc 2.3有性能改进测量

自glibc 2.16以来,Glibc也使用每个线程的内存池

因此,现在已经没有性能差异

Fedora [我们]曾经一段时间使用tcmalloc来为QEMU分配内存。然后我们再次检查性能,发现与glibc的本地malloc相比的差距基本上已经消失了

还要注意C++ new操作符调用由libc(大多数情况下是glibc malloc)提供的malloc函数。

所以:

  1. 不,这种行为没有被标准化。
  2. 它仅在每个线程中使用一个池(并且仅当您使用glibc >= 2.16时),否则您可以尝试使用TCMalloc进行编译。

1
Hoard和Intel的TBB Allocator采用了类似于TCMalloc的方法。它们使用每个线程的池分配器,结合锁定机制(在某些代码路径上)来处理跨线程的释放。两者都使用每个线程的多个分配池,以分配各种大小的固定大小对象,以将最坏情况的碎片化限制在一定的百分比值内。总体而言,它们具有非常高的性能,但是,“池的大小可能难以评估”您所说的意思不太清楚——如果这是指确定从操作系统分配的总内存量,则很容易跟踪。 - Lux

0

C++17 开始在多线程应用程序中指定分配器的行为:


在 C 语言中,从版本 2.16 开始,glibc 为每个线程提供了一个内存池:http://patchwork.sourceware.org/patch/19042/ - Jérôme Pouiller

0
所有多线程程序分析,我都是使用Intel Parallel Studio(在Windows下)进行的,它总是显示锁事件和内核时间由于分配而产生。
这意味着VS'08编译器中的C++ new主要使用互斥锁来保持内存一致性。
每当这成为我开发的软件中的一个问题时,我尝试使用RIA习语并移除动态/共享内存,或者如果内存只需要被线程本身使用,则使用TLS分配器。

你如何称呼RIA习语? - Jérôme Pouiller
对不起,我打错了一个字,我想说的是RAII(资源获取即初始化)。但在你的情况下,“它是一种...”。当你实例化一个对象或线程时,会分配和初始化之后使用的所有内存和变量,或者减少最小动态内存使用。 - alexbuisson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接