我需要动态分配一个小类(32位系统上的16个字节)。在大多数情况下,任何给定实例的生命周期都非常短。某些实例也可以跨线程边界传递。
做了一些分析后,我发现我的程序似乎花费了更多的时间来分配和解除分配,而不是实际花费使用它们所以我想用更高效的东西替换默认的new和delete。 p>
对于一个大对象(db连接,因为它发生,构造而不是分配是昂贵的),我已经使用了一个池系统,但是它涉及一个用于存储“free”对象的列表,还有一个mutex用于线程安全。在互斥锁和列表之间,它实际上比小对象的基本新建/删除更糟糕。
我在Google上发现了一些小对象分配器,但它们似乎使用的是一个全局/静态池,它没有以线程安全的方式使用,这使得它们不适合我的使用:(
我为这些小物件进行有效的内存管理还有哪些其他选择?
答案 0 :(得分:1)
也许尝试使用Google的tcmalloc?它针对线程程序中的快速分配/解除分配进行了优化,并且对于小型对象具有较低的开销。
答案 1 :(得分:1)
某些实例也可能跨越线程边界传递
只有“一些”?所以也许你可以负担得起为这些付出额外的费用,如果它使那些没有传递到其他线程的那些更便宜。我可以通过各种方式考虑每个线程获得一个分配器,并避免在分配器所属的线程中分配或释放时需要锁定。我不知道你的程序可能有哪些:
跨越线程边界复制内容,而不是传递它们。
安排如果因任何原因将它们传递给另一个线程,那么它们将被传递回原始线程以释放。这不一定非常频繁发生,您可以在接收线程中排队一些,然后在消息中将它们全部传回。这当然假设拥有分配器的线程将会坚持下去。
每个分配器有两个空闲列表,一个是同步的(当它们从另一个线程中释放时添加了哪些对象),另一个是不同步的。仅当非同步列表为空且您正在分配(因此在拥有分配器的线程中)时,是否需要锁定同步的空闲列表并将其所有当前内容移动到非同步列表。如果传递给其他线程的对象很少,这基本上消除了对互斥锁的争用,并大大减少了它的使用次数。
如果上述所有方法都失败了,每个线程有一个分配器可能仍然允许你摆脱互斥锁并使用无锁队列来释放空闲列表(多个写入器释放,单个读取器分配),这可能稍微提高性能。实现无锁队列是特定于平台的。
更进一步,您的应用程序是否经常处于这样一种状态:您知道在某个点(可能是过去的一点点)之后分配的所有单元格都不再使用了?如果是这样,并假设你的小物体的析构函数没有做任何非常紧急的事情,那么根本不打扰释放单元格 - 在“特定点”创建一个新的分配器并将旧的分配器标记为不再使用新的分配。当你“击中状态”时,释放整个分配器及其底层缓冲区。如果“特定点”和“状态”是同时的,那么更容易 - 只需重置你的分配器。
答案 2 :(得分:0)
您可以确保使用low fragmentation heap。默认情况下,它在Vista及更高版本中启用,但我不认为早期操作系统会如此。这可以对小物体的分配速度产生很大的影响。