使用realloc函数和free -> malloc函数之间的区别

43
为什么要使用 realloc() 函数来重新调整动态分配数组的大小,而不是在调用 malloc() 函数之前使用 free() 函数(即优缺点、优势与劣势等)?这适用于 C 语言编程,但我找不到适当的标签。提前感谢您。

如果您不关心内存的内容,为什么需要内存呢? - Philip
5个回答

49

虽然内存管理在不同系统中存在差异,因此这个基准测试并不是最终的参考指标,但现在的情况往往比较标准化,因此这些结果应该是安全的参考点(如果您知道一个实际案例与此不符,请告诉我)。我正在使用Windows 7,搭载2.10GHz四核Intel Core i3 2310M处理器和4GB的内存,虽然不是最好的硬件,但是目前是我能用到的最好的。

这个基准测试会从一定量的内存(INITIAL_MEMORY)开始,并重复以小量(BYTE_STEP)为单位的重新分配,直至完全分配/释放ALLOCATE_MEMORY。为此,它尝试了6种方法:

  1. 增加有损Malloc:free()和malloc()更多的内存。
  2. 减少有损Malloc:free()和malloc()更少的内存。
  3. 增加Malloc:malloc()更多的内存,复制数据并free()先前的内存。
  4. 减少Malloc:malloc()更少的内存,复制数据并free()先前的内存。
  5. 增加Realloc:realloc()更多的内存。
  6. 减少Realloc:realloc()更少的内存。

那么,第一个测试:从2MB开始,以1KB的步长分配±1MB:

Increasing Lossful Malloc took 3 ms
Decreasing Lossful Malloc took 5 ms
Increasing Malloc took 1 265 ms
Decreasing Malloc took 744 ms
Increasing Realloc took 316 ms
Decreasing Realloc took 0 ms

正如我们所看到的,使用memcpy手动复制始终比realloc慢,因为在这种情况下,malloc保证分配新内存,并且您被迫在每次分配中复制数据,这表明realloc确实在某些情况下重用相同的地址并增加块大小。因此,如果你想保留你的数据,可能需要使用realloc。为了简化问题,我不会继续测试这种无损malloc方法。

让我们继续进行下一个测试:32MB初始内存,16MB以16KB步长分配:

Increasing Lossful Malloc took 4 ms
Decreasing Lossful Malloc took 4 ms
Increasing Realloc took 21 453 ms
Decreasing Realloc took 0 ms

现在我们可以看到,相对于其他测试,增加realloc需要非常长的时间。减少realloc甚至还没有达到1毫秒。这表明如果您不想保留内存,您应该使用free->malloc方法,或者呢?请看下面的结果:

Increasing Lossful Malloc took 777 ms
Decreasing Lossful Malloc took 729 ms
Decreasing Realloc took 19 ms

(这些结果非常接近,所以我运行了几个测试并对它们进行了平均。)

当使用realloc()时,显然减小内存大小更加高效。这可能是因为realloc不需要寻找新的内存块,它只使用之前的内存块并缩小它。如果您正在大量分配内存,则性能差异很大。

此外,我们可以看到,即使两者基本上执行相同的操作:查找内存块并分配它们,增加malloc()的速度也略慢于减小的速度。这种差异可能是因为在搜索较大内存块时,malloc需要花费更长的时间来搜索平均值,而在搜索较小内存块时,malloc需要花费更少的时间。例如,如果有一个30MB的内存块,分配16MB的malloc会使用它,但分配32MB的malloc将不得不跳过它并继续搜索,从而浪费时间。这可能是我的测试结果如此不同的原因。

总之/TLDR:

  1. 如果你需要保留数据,请使用realloc()。与使用malloc()/free()并在扩大规模时复制数据相比,它的速度快约4倍。在缩小规模时,它快10,000-100,000倍。永远不要手动复制数据。
  2. 如果你不需要保留数据,请使用malloc()/free()在扩大内存大小时,但在减小内存大小时请使用realloc()。
  3. 如果你不知道上一个大小(你不知道你是在缩小还是扩大),请使用malloc()/free()。在缩小规模时,realloc()的速度快约40倍,但在扩大规模时,realloc()的速度慢约7600倍。除非您的程序进行了一些巨大的分配和大量的小型释放(比分配多约200倍,并可能出现这种情况),否则您应该使用malloc()/free()。

这是我的基准源代码:test.cpp


34

realloc的优点在于它会保留内存的内容。如果使用free + malloc的话,需要重设数组中的数据。


9
如果您对数据保存不感兴趣,则使用free和malloc可能在某些情况下更快(例如由于尺寸增长而需要移动内存块),但这也是一个缺点。 - Toad
11
如果需要缩小内存,使用realloc会更快;如果有足够的空间进行扩展,则使用realloc进行内存扩展可能也比较快。否则,将转换成malloc/copy/free的操作。 - Steven Sudit
2
如果您不需要保留数据,使用free和malloc似乎更能描述您正在进行的操作。 - Toad
如果您不需要保留数据,那么无论如何复制它的成本可能是禁止性的。 - Steven Sudit
我并不关心内存的内容,供你参考。 - stanigator
2
然后按顺序释放旧缓冲区并分配新缓冲区。任何体面的malloc()实现都会高效处理这种情况。试图通过使用realloc()来优化这种情况最终将是失败的。 - bbum

7

realloc(重新分配内存)可以原地更改块的大小,或分配一个新的块并复制尽可能多的内容。相比之下,malloc和free只能分配一个新的块,并且您必须自己执行复制操作。

坦率地说,由于realloc与C ++不兼容,它在今天的使用中并不常见。因此,内存管理器倾向于不针对其进行优化。


1
你关于realloc和内存管理器不优化它的说法 - 你是否阅读过相关资料? - ArmenB
@ArmenB。我不确定2009年的时候我在想什么,但是我最近查看了TCMalloc的代码,发现它并不真正面向调整大小。 - Steven Sudit

4

我有一个程序,通过调用free()和malloc()函数创建动态数组。我想通过重复使用现有的数组来优化它。然而,基准测试表明,平均而言,realloc()的速度比仅仅调用free()和malloc()要慢。我猜这是有道理的,因为有时候数组会增长,可能需要进行复制。


2

"在再次调用malloc()函数之前,不要使用free()函数"

如果你释放了现有的数组,就会丢失所有内容,因此你不能像通常那样“增加”数组。


2
我相信他们的意思是调用malloc,复制内容,然后释放内存。 - Steven Sudit
Steven刚刚说了我的意思。 - stanigator

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