有效分配许多短命的小对象 [英] Efficiently allocating many short-lived small objects

查看:109
本文介绍了有效分配许多短命的小对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小类(32位系统上的16个字节),我需要动态分配。在大多数情况下,任何给定实例的生命周期都很短。一些实例也可以通过线程边界传递。



我做了一些分析,我发现我的程序似乎花费更多的时间分配和释放的东西,而不是实际支出使用它们,所以我想替换默认的新和删除更有效的东西。



对于一个大对象(db连接,因为它发生,这是昂贵的构造而不是分配),我已经使用一个池系统,但涉及到一个列表,用于存储自由对象,还有一个互斥量的线程安全。在互斥体和列表之间,它实际上比小对象的基本新/删除更糟糕。



我在Google上发现了一些小的对象分配器,似乎使用一个全局/静态池,这不是以线程安全的方式使用,使它们不适合我的使用:(



我有效的其他选项

一些实例也可以通过线程边界传递

p>

只有some?所以也许你可以支付额外的费用,如果它使那些不通过其他线程更便宜。可以想到得到每个线程一个分配器,避免在分配器所属的线程中分配或释放时需要锁定。我不知道你的程序中可能有哪些可能:



  • 将整个线程边界复制而不是传递。它们由于任何原因传递到另一个线程,然后它们被传递回原始线程以释放。这不一定非得经常发生,你可以排队接收线程中的几个,并将它们全部传回一个消息后。这假定拥有分配器的线程将会停止。


  • 每个分配器有两个空闲列表,一个已同步当他们从另一个线程释放时),一个未同步。只有当非同步列表为空,并且你正在分配(因此在拥有分配器的线程中),你需要锁定同步的自由列表,并将其所有当前内容移动到未同步的列表。如果对象被传递给其他线程是罕见的,这基本上消除了对互斥体的争用,大量减少了它的所有次数。


  • 如果所有上面的失败,每个线程有一个分配器可能仍然允许你摆脱互斥,并使用一个无锁队列的空闲列表(多个写作器释放,单个读卡器分配),这可以提高性能一点。实施无锁队列是特定于平台的。




再往前走一步,状态,其中你知道所有单元格分配后某一点(也许在过去一点),不再使用?如果是这样,并假设你的小对象的析构函数没有做任何非常紧急,那么不要打扰释放细胞 - 在某一点创建一个新的分配器,并标记旧的不再使用新分配。当命中状态时,释放整个分配器及其底层缓冲区。如果特定点和状态是同时的,所有更容易 - 只需重置您的分配器。


I've got a small class (16 bytes on a 32bit system) which I need to dynamically allocate. In most cases the life-time of any given instance is very short. Some instances may also be passed across thread boundaries.

Having done some profiling, I found that my program appears to be spending more time allocating and deallocating the things than it's actually spending using them so I want to replace the default new and delete with something that a little more efficient.

For a large object (db connections as it happens, which are expensive to construct rather than allocate), I'm already using a pooling system, however that involves a list for storing the "free" objects, and also a mutex for thread safety. Between the mutex and the list it actually performs worse than with the basic new/delete for the small objects.

I found a number of small object allocators on Google, however they seem to be using a global/static pool which is not used in a thread safe manner, making them unsuitable for my use :(

What other options have I got for efficient memory management of such small objects?

解决方案

Some instances may also be passed across thread boundaries

Only "some"? So perhaps you can afford to pay extra for these, if it makes the ones that don't get passed to other threads cheaper. There are various ways I can think of to get to one allocator per thread and avoid the need to lock when allocating or freeing in the thread to which the allocator belongs. I don't know which might be possible in your program:

  • Copy things across the thread boundary, instead of passing them.

  • Arrange that if they're passed to another thread for any reason, then they're passed back to the original thread to free. This doesn't necessarily have to happen very often, you could queue up a few in the receiving thread and pass them all back in a message later. This assumes of course that the thread which owns the allocator is going to stick around.

  • Have two free lists per allocator, one synchronised (to which objects are added when they're freed from another thread), and one unsynchronised. Only if the unsynchronised list is empty, and you're allocating (and hence in the thread which owns the allocator), do you need to lock the synchronised free list and move all of its current contents to the unsynchronised list. If objects being passed to other threads is rare, this basically eliminates contention on the mutex and massively reduces the number of times it's taken at all.

  • If all the above fails, having one allocator per thread might still allow you to get rid of the mutex and use a lock-free queue for the free list (multiple writers freeing, single reader allocating), which could improve performance a bit. Implementing a lock-free queue is platform-specific.

Taking a step further back, does your app frequently hit a state in which you know that all cells allocated after a certain point (perhaps a little in the past), are no longer in use? If so, and assuming the destructor of your small objects doesn't do anything terribly urgent, then don't bother freeing cells at all - at the "certain point" create a new allocator and mark the old one as no longer in use for new allocations. When you "hit the state", free the whole allocator and its underlying buffer. If the "certain point" and the "state" are simultaneous, all the easier - just reset your allocator.

这篇关于有效分配许多短命的小对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆