如何在多线程环境中使用new
?
准确地说:我有一段用40个线程运行的代码。每个线程调用new
几次。我注意到性能下降,可能是因为线程锁定在new
(在__lll_lock_wait_parallel
和__lll_unlock_wait_parallel
中花费了大量时间)。我可以使用new
/ delete
的最佳替代方案是什么?
相关:
答案 0 :(得分:5)
我不知道“最好的”,但我会尝试一些事情:
降低分配/释放的频率(可能很难)。如果能提高性能,就浪费内存(但不要泄漏)
滚动我自己的每线程分配器并始终使用mmap
为同一个线程分配/释放实际内存
滚动你自己的原始分配器:
mmap
从操作系统中获取大量内存我不认为这样做是微不足道的,但如果做得好,它可以提高性能。最毛茸茸的部分是到目前为止跟踪分配,防止碎片等。
本书末尾附近的“ The C Programming Language ”中提供了一个简单的实现(但它使用了brk
IIRC)。
答案 1 :(得分:5)
即使您使用new
运算符,它也会使用下面的malloc
进行分配和释放。重点应放在分配器上,而不是在这些情况下用于达到它的API。
TCMalloc 是专为在多线程环境中获得良好性能而在Google创建的malloc。它是google-perf-tools的一部分。
您可能会看到的另一个malloc是 Hoard 。它与TCMalloc的目标大致相同。
答案 2 :(得分:2)
我认为你应该使用内存池。在项目启动时第一次分配所需的所有内存(如果大小为Fix),并让数组从您分配的第一个数组中获取所需的内存。
答案 3 :(得分:1)
我倾向于在服务器和其他此类应用程序中使用对象池,这些应用程序的特点是持续且频繁地分配和释放大量的几组对象(在服务器中 - 套接字,缓冲区和缓冲区集合类)。这些池是队列,在启动时创建并推送适当数量的实例(例如,我的服务器 - 24000个套接字,48000个集合以及7个不同大小/数量的缓冲池池阵列)。从队列中弹出对象实例并将其重新启动比新/删除要快得多,即使池队列具有锁定,因为它在线程之间共享,(锁定范围越小,争用的可能性越小) 。我的池对象类(从中继承了所有套接字等),有一个私有的'myPool'成员,(在启动时加载)和一个没有参数的'release()'方法&所以任何缓冲区都可以轻松,正确地返回到自己的池中。有问题:
1)Ctor和dtor不会被分配/释放&所以分配的对象包含他们上次使用时留下的所有gunge。这有时可能是有用的(例如,可重用的套接字对象),但通常意味着需要注意,例如,布尔值的初始状态,int的值等等。
2)每个线程的池具有最大的性能改进潜力 - 不需要锁定,但是在每个线程上的加载是间歇性的系统中,这可能是对象浪费。我似乎永远无法逃避这一点,主要是因为我使用池化对象进行线程间通信,因此无论如何release()都必须是线程安全的。
3)消除共享池上的“错误共享”可能很尴尬 - 每个实例应该最初“新建”,以便专门使用整数个缓存页面。至少这只需要在启动时完成一次。
4)如果系统要在池耗尽时恢复弹性,则需要分配更多对象以在需要时添加到池中(池大小随后逐渐增加),或者生产者 - 消费者队列可以使用以便线程在池上阻塞直到释放对象,(由于condvar / semaphore /等待线程阻塞的PC队列速度较慢,在释放之前分配的线程也会在空池上死锁)。
5)需要在开发期间监视池级别,以便可以检测到对象泄漏和双重释放。可以将代码/数据添加到对象/池中以检测发生的错误,但这会影响性能。
答案 4 :(得分:1)
2,如果您的开发环境支持它,请查看http://en.wikipedia.org/wiki/Thread-local_storage ...
答案 5 :(得分:0)
由于没有人提及它,我可能还建议尝试使用Boehm's conservative garbage collector;这意味着使用new(gc)
代替new
,GC_malloc
代替malloc
而不用担心free
- 或delete
内存对象。几年前,我测量GC_malloc
与malloc
,它有点慢(GC_malloc
可能为25μs而系统malloc
则为22μs。)
我不知道Boehm的GC在多线程使用中的性能(但我知道它可以在多线程应用程序中使用)。
Boehm的GC的优势在于您不应该关心free
您的数据。