C/C++内存分配按块分配

3
给定以下情况,就空间/时间消耗而言,最适合的跨平台方法是什么:
(1) 在某个时间点,一组对象的总大小已知。因此,所需的内存可以一次性分配。
(2) 内存所有权需要分配给每个单独的对象,并且释放(解除分配)的时间未确定。
我建议采用某种内存块引用计数的临时方法。每当对象被释放时,引用计数都会减少。当达到零时,大块内存才会被释放。
是否有更适合的模式或常见做法?

1
这是非常有用的: https://www.ibm.com/developerworks/aix/tutorials/au-memorymanager/ - didiz
1
这取决于您使用的C++版本,但现代版本(或通过boost)将为您提供托管指针,这基本上会为您执行引用计数。 - Neil
1
对已分配的块进行引用计数听起来像在另一个分配器之上构建分配器。你可能想要的是一个固定大小的分配器,它允许有效地管理相同大小的对象。 - Passer By
1个回答

3
给定的情况不足以确定“最佳”方法。
(1)在某个时间点,一组对象的总大小是已知的。因此,可以在一次分配中分配所需的内存。
如果所有分配都发生在程序的初始部分,那么这个事实对我们没有帮助(除非它对加快启动时间至关重要)。如果程序频繁地销毁和创建新对象,那么这也没有帮助,因为内存分配器从未将其堆内存释放回操作系统;它只为未来的自己使用而释放它。
唯一有用的情况是,在程序的生命周期内发生的所有对象分配和取消分配都是相同类型的对象。在这种情况下,内存池实现将提高性能,因为查找下一个可用于分配的插槽始终是O(1)。以下是一个示例实现(source)。
如果您还知道每种对象类型的对象总大小,则多个内存池也非常有用。如果不是这种情况,那么您可以将所有对象舍入到最大对象大小,并在浪费内存的情况下提高性能(使用内存池)。
(2) 内存所有权需要分配给每个单独的对象,并且释放(deallocation)的时间是不确定的。 处理对象的生命周期很困难,最佳方法取决于以下三个问题: - 单个对象有多少引用? - 这个对象被传递了多少次? - 您的对象图包含循环吗? 如果这些问题的答案是“几个、不多、没有”,那么 std::shared_ptr<> 可能非常有用。然而,如果引用数量不是那么小或者对象经常从手中传递,那么引用计数可能会在每次交接时产生重大开销。如果您的对象图中存在循环,则发生内存泄漏。在这种情况下,垃圾回收解决方案很可能具有更好的性能,并且更容易管理(请参见Boeham的C和C++实现)。
我的临时解决方案是在分配的内存块上实现某种引用计数。每当对象被释放时,引用计数就会减少。当其为零时,大块内存将被释放。
考虑到free()函数并没有真正释放内存回操作系统,我认为这种方法没有任何好处。你只会增加更多的管理开销而不获得任何性能提升。你在问题中没有提到需要将内存释放回操作系统,所以我想这不是一个问题。
有没有更合适的模式或常见做法?
最显著的改进是通过消除使用通用内存管理来实现,因为它是为通用目的而设计的。它考虑了所有情况,因此性能相对较差。例如,管理线程之间的同步。

如果您不使用多个线程且适用于内存池解决方案,请使用它们;它们可能具有最佳性能,并且非常简单。 如果内存池不适用,和/或者您的程序使用了许多线程,则我会选择其中许多替代内存分配器之一。我知道一个很好的多线程内存分配器是Hoard


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接