动态内存分配的线程争用

Posted

技术标签:

【中文标题】动态内存分配的线程争用【英文标题】:thread contention on dynamic memory allocation 【发布时间】:2010-10-10 20:58:07 【问题描述】:

我刚刚了解到,在 C 语言中,malloc 函数在多线程应用程序中使用时会出现线程争用问题。

在 C++ 中,operator new 会遇到同样的问题吗?如果是,我可以使用什么技术来避免这听起来像是对应用程序性能的重大损失?

【问题讨论】:

原则上是的,但是直到你测量你才知道实际的惩罚。根据平台/编译器和您的算法,它可以忽略不计。如果您在 malloc 上花费大量时间,那么也该重新考虑不同的算法了。 【参考方案1】:

线程争用的“问题”实际上取决于实现。一些常用的 malloc 实现最初设计时并未考虑多线程。但是为多线程应用程序设计的 malloc 实现在正常情况下不应该出现争用。

作为考虑多线程设计的 malloc 实现示例,请查看 jemalloc。

【讨论】:

【参考方案2】:

取决于 new 的实现,但通常是基于 malloc 的。 这里有几件事你可以做:

使用分析器计算每秒调用malloc()(可能还有brk())的次数,确保您有malloc() 的争用问题。 尝试使用并行内存分配器(即hoard) 尽可能使用堆栈:不要在不需要时调用 new。 另请记住,小副本通常比线程间共享的指针和数据更易于缓存。

【讨论】:

【参考方案3】:

在 C++ 中,运算符 new 是否会遇到同样的问题?

是的,在大多数实现中,确实如此。

如果您已经使用 C++,Threading Building Blocks 是一个 C++ 模板库,应该可以满足您的需求。它具有可扩展的分配器、数据结构、website 等等...

【讨论】:

【参考方案4】:

malloc 中线程争用的问题很简单,就是堆在更新时必须受到类似设备的互斥体的保护。如果两个线程同时更新堆,您将遇到竞争条件。同样的问题也适用于新的,所以没有根本原因为什么一个应该比下一个少。

话虽如此,有许多技巧可以最大限度地减少争用。首先是将堆分解为单独的竞技场。每个竞技场都有自己的锁。如果一个线程尝试分配内存并且一个 Arena 被锁定,它只会尝试分配下一个 Arena。

Frees 需要访问用于 malloc 的同一个 Arena。这也可以通过将要释放的指针放在空闲列表中来优化。这可以原子地完成。下一次 Arena 解锁时,free list 上的所有指针都会被正确释放。

这些技术有助于防止但不能消除争用,这意味着在生产者消费者线程模型中,最好让消费者将指针传回生产者,以便在适当的时候重用或删除它们。

【讨论】:

以上是关于动态内存分配的线程争用的主要内容,如果未能解决你的问题,请参考以下文章

动态内存与智能指针

Java如何分配和回收内存?Java垃圾收集器如何工作?

OpenMP 中的 C++ 动态内存分配速度较慢,即使对于非并行代码段也是如此

c语言中啥是动态分配内存?

C语言中的动态内存分配的用法举例

动态内存分配