最小化malloc()调用的数量可以提高性能?

时间:2010-01-16 22:35:51

标签: c malloc

考虑两个应用程序:一个(num.1)多次调用malloc(),另一个(num.2)调用malloc()几次。 两个应用程序都分配相同的内存量(假设为100MB) 对于哪个应用程序,下一个malloc()调用会更快,#1或#2?
换句话说:malloc()在内存中是否有分配位置的索引?

8 个答案:

答案 0 :(得分:19)

你问了两个问题:

  • 对于哪个应用程序,下一个malloc()调用会更快,#1还是#2?
  • 换句话说:malloc()是否在内存中分配了位置索引?

你暗示他们是同一个问题,但他们不是。后一个问题的答案是肯定的。

哪个更快,不可能说。它取决于分配器算法,机器状态,当前进程中的碎片等。

但您的想法是合理的:您应该考虑malloc的使用将如何影响性能。 曾经有一个我编写的应用程序使用了大量的内存小块,每个都分配了malloc()。它工作正常,但很慢。我用一个替换了对malloc的许多调用,然后在我的app中切掉了那个大块。它要快得多。

我不推荐这种方法;它只是说明了malloc的使用会对性能产生重大影响。

我的建议是衡量它

答案 1 :(得分:10)

当然这完全取决于malloc实现,但在这种情况下,没有调用free,大多数malloc实现可能会给你相同的算法速度。

正如另一个回答评论的那样,通常会有一个空闲块列表,但是如果你没有自由调用,那么只有一个,所以在两种情况下都应该是O(1)。

这假设在两种情况下为堆分配的内存都足够大。在#1的情况下,你将分配更多的总内存,因为每个分配都涉及存储元数据的内存开销,因此你可能需要调用sbrk(),或等效于在#1的情况下增长堆,这将增加额外的开销。

由于缓存和其他二阶效应,它们可能会有所不同,因为新分配的内存对齐方式不一样。

如果你已经释放了一些内存块,那么由于碎片较少,#2可能会更快,因此可以搜索更小的空闲块列表。

如果你已经释放了所有的内存块,它应该最终完全相同,因为任何无理性的实现都会将块合并回一个单独的内存区域。

答案 2 :(得分:6)

Malloc必须运行一个空闲块的链接列表才能找到要分配的空闲块。这需要时间。所以,#1通常会变慢:

  • 您拨打malloc的次数越多,所需的时间就越多 - 因此减少通话次数会使您的速度得到提升(尽管它是否具有重要意义取决于您的具体情况)。

  • 此外,如果你使用malloc许多小块,那么当你释放这些块时,你将比分配和释放一些大块更多地分割堆。因此,您可能最终会在堆上放置许多小的空闲块而不是几个大块,因此您的malloc可能必须进一步搜索可用空间列表以找到合适的块来分配。再次使它们变慢。

答案 3 :(得分:3)

这些当然是实现细节,但通常free()会将内存插入到空闲块列表中。然后,malloc()会查看此列表中是否有正确大小或更大的空闲块。通常,只有在此失败的情况下malloc()才会要求内核提供更多内存。

还有其他一些注意事项,例如何时将多个相邻块合并为一个更大的块。

malloc()代价高昂的另一个原因是:如果从多个线程调用malloc(),则必须在这些全局结构上进行某种同步。 (即锁定。)存在具有不同优化方案的malloc()实现,以使其更适合多线程,但通常,保持多线程安全会增加成本,因为多个线程将争用这些锁并阻止进度在彼此身上。

答案 4 :(得分:2)

答案是,它取决于,大多数潜在的缓慢而不是来自malloc()和free()的组合,通常#1和#2的速度相似。

所有malloc()实现都有一个索引机制,但是向索引添加新块的速度通常不依赖于索引中已有的块数。

malloc的大部分缓慢来自两个来源

  • 在先前释放的(块)中搜索合适的空闲块
  • 锁定多处理器问题

编写我自己几乎符合标准的malloc()替换工具malloc()&& free()次数从35%到3-4%,并且它严重优化了这两个因素。它可能与使用其他高性能malloc的速度相似,但拥有我们自己的更容易使用深奥的设备,当然也允许在某些地方自由内联。

答案 5 :(得分:2)

你可以总是使用malloc()做更好的工作来分配大块内存并自己进行细分。 Malloc()经过优化,可以在一般情况下运行良好,并且不会假设您是否使用线程或程序分配的大小。

实现自己的子分配器是否是个好主意是次要问题。很少,显式内存管理已经足够困难了。你很少需要另一层代码,这些代码可以搞砸你的程序而没有任何好的方法来调试它。除非您正在编写调试分配器。

答案 6 :(得分:1)

你没有定义“很多”和“很少”之间的相对差异,但我怀疑大多数malloc在两种情况下几乎完全相同。问题意味着每次调用malloc都会产生与系统调用和页表更新一样多的开销。当你进行malloc调用时,例如malloc(14),在非脑死环境中,malloc实际上会分配比你要求的更多的内存,通常是系统MMU页面大小的倍数。你获得了14个字节,malloc跟踪新分配的区域,以便以后的调用只返回已经分配的内存块,直到需要从操作系统请求更多的内存。

换句话说,如果我将malloc(14)调用100次或者调用malloc(1400)一次,则开销大致相同。我只需要自己管理更大的分配内存块。

答案 7 :(得分:1)

分配一块内存比分配多块更快。有系统调用的开销,也搜索可用的块。在编程中减少操作次数通常会加快执行时间。

内存分配器可能必须搜索以找到大小正确的内存块。这增加了执行时间的开销。

但是,在分配小块内存而不是一个大块时,可能会有更好的成功机会。您的程序是分配一个小块并释放它还是需要分配(并保留)小块。当内存碎片化时,可用的块数较少,因此内存分配器可能必须合并所有块以形成足够大的块以进行分配。

如果您的程序正在分配和销毁许多小块内存,您可能需要考虑分配静态数组并将其用于内存。