Malloc / new锁和多线程
malloc / new lock and multithreading
如何在多线程环境中使用new
?
准确地说:我有一段代码,我用40个线程运行。每个线程调用new
几次。我注意到性能下降,可能是因为线程锁定在new
中(在__lll_lock_wait_parallel
和__lll_unlock_wait_parallel
中花费了大量时间)。我可以使用的new
/delete
的最佳替代方案是什么?
- http://dsc.sun.com/solaris/articles/multiproc/multiproc.html
malloc线程安全吗?
即使您正在使用new
操作符,它也在下面使用malloc
来进行分配和释放。在这些情况下,重点应该放在分配器上,而不是用来访问它的API。
TCMalloc 是Google专门为多线程环境下的良好性能而创建的malloc。是google-perf-tools的一部分。
另一个malloc是Hoard。它的目标与TCMalloc大致相同。我不知道什么是"最好的",但我会尝试一些事情:
-
减少分配/释放的频率(可能很难)。如果可以提高性能,就浪费内存(但不要泄漏)
-
滚动我自己的,每线程分配器,并始终使用
mmap
分配/释放同一线程的实际内存
滚动您自己的原语分配器:
- 使用
mmap
从OS获取大块内存 - 使用数据结构(链表,树等)来跟踪空闲和已使用的块
- 永远不要释放其他线程分配的数据
我不认为这是微不足道的,但如果做得好,它可以提高性能。到目前为止,最棘手的部分是跟踪分配,防止碎片等。
在本书末尾的" C编程语言"中提供了一个简单的实现(但它使用brk
IIRC)。
我认为你应该使用内存池。在项目开始时第一次分配所需的所有内存(如果size为Fix),并让数组从分配的第一个数组中获得所需的内存。
我倾向于在服务器和其他这样的应用程序中使用对象池,这些应用程序的特点是持续频繁地分配和释放大量的少数对象集(在服务器中-套接字,缓冲区和缓冲区收集类)。池是队列,在启动时创建,并推送适当数量的实例。我的服务器- 24000套接字,48000个集合和7个不同大小/计数的缓冲区池的数组。将对象实例从队列中弹出并将其推回到队列中比new/delete要快得多,即使池队列具有锁,因为它是跨线程共享的(锁跨度越小,争用的可能性越小)。我的池对象类(继承了所有套接字等)有一个私有的'myPool'成员(在启动时加载)和一个'release()'方法,没有参数&因此,任何缓冲区都可以轻松且正确地返回到自己的池中。有问题:
1)分配/释放时不调用Ctor和dtor;因此,分配的对象包含了它们最后一次使用时剩下的所有资源。这有时是有用的。可重用的套接字对象),但通常意味着需要注意,例如,布尔值的初始状态,int值等。
2)每个线程的池具有最大的性能改进潜力-不需要锁定,但在每个线程的加载是间歇性的系统中,这可能是一个对象浪费。我似乎从来没有能够摆脱这一点,主要是因为我使用池对象进行线程间通信,所以release()无论如何都必须是线程安全的。
3)消除共享池上的"虚假共享"可能会很尴尬-每个实例最初都应该是"新"的,以便独占地使用一个整数的缓存页面。至少这只需要在启动时做一次。
4)如果系统弹性在池耗尽,要么需要分配更多的对象可以在需要的时候添加到池中,(然后爬池大小),或生产者消费者队列可以这样使用线程块池在对象被释放之前,(pci队列更慢,因为condvar/信号/无论等待线程块,还死锁线程分配释放之前空池)。
5)需要在开发期间监视池的水平,以便可以检测到对象泄漏和双重释放。可以将代码/数据添加到对象/池中,以便在发生此类错误时进行检测,但这会影响性能。
第一,你真的要"new"那个东西吗?为什么不使用局部变量或每个线程的堆对象呢?
第二,看看http://en.wikipedia.org/wiki/Thread-local_storage,如果你的开发环境支持它…
既然没有人提到它,我也可能建议尝试使用Boehm的保守垃圾收集器;这意味着使用new(gc)
代替new
, GC_malloc
代替malloc
,不要为free
-ing或delete
-ing内存对象而烦恼。几年前,我测量了GC_malloc
和malloc
,它有点慢(GC_malloc
可能是25µs,而malloc
系统是22µs)。
我不知道Boehm的GC在多线程使用中的性能(但我知道它可以在多线程应用程序中使用)。
Boehm的GC的优点是您不应该关心数据的free
。
- 在C++中使用cURL和多线程
- 多线程双缓冲区
- 为什么我的多线程作业队列崩溃
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 为什么一个向量上的多线程操作很慢
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 全局变量 多读取器 一个写入器多线程安全?
- boost::文件系统::recursive_directory_iterator多线程安全
- 如何阻止TensorFlow的多线程
- 如何在多线程中正确使用unique_ptr进行多态性?
- 并发/多线程:是否可以以这种方式生成相同的输出?
- sigwait() 在多线程程序中不起作用
- 多线程程序中出现意外的内存泄漏
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 多线程比没有线程C++慢
- 具有 C++11 多线程的特征库
- 为多线程环境包装 c++ new/delete 的安全/好方法
- Malloc / new锁和多线程
- New和delete处理多线程问题