calloc 和 malloc 的时间效率对比

18

我很感兴趣地阅读了这篇文章 C difference between malloc and calloc。 我在我的代码中使用malloc,并想知道如果使用calloc会有什么不同。

我现在使用malloc的(伪)代码:

场景1

int main()
{  
   allocate large arrays with malloc

   INITIALIZE ALL ARRAY ELEMENTS TO ZERO

   for loop //say 1000 times
    do something and write results to arrays
   end for loop

   FREE ARRAYS with free command

} //end main
如果我使用calloc而不是malloc,那么我将会得到:

场景2

int main()
{  

   for loop //say 1000 times
    ALLOCATION OF ARRAYS WITH CALLOC 

    do something and write results to arrays

    FREE ARRAYS with free command

   end for loop


} //end main

我有三个问题:

  1. 如果数组非常大,哪种情况更有效率?

  2. 如果数组非常大,哪种情况的时间效率更高?

  3. 在这两种情况下,我只是按顺序向数组写入内容,对于循环的任何给定迭代,我都是按顺序从第一个元素到最后一个元素逐个写入每个数组。重要的问题是:如果我像方案1中使用malloc,那么初始化元素为零是否必需?假设使用malloc后,我得到了数组z=[垃圾1,垃圾2,垃圾3]。在每次迭代中,我都是依次写入元素,即在第一次迭代中,我得到了z=[某些结果,垃圾2,垃圾3],在第二次迭代中,我得到了z=[某些结果,另一个结果,垃圾3],以此类推,那么我是否需要在malloc之后特别初始化我的数组?


可能是https://dev59.com/1XI_5IYBdhLWcg3wEexu的重复问题。 - Roger Pate
是的,这就是为什么我提到我读了另一篇帖子。我想在这里更具体一些。 - yCalleecharan
你自己测量过吗?在你的机器上结果如何? - Secure
还没有。如果有差异,我会回来写的。 - yCalleecharan
1
这里有一个相关的(稍后的)问题,涉及到为什么calloc比malloc+memset快得多(10倍)。https://dev59.com/7XE85IYBdhLWcg3wnU6p - Dietrich Epp
7个回答

19
假设两个示例中初始化的内存总量相同,则用calloc()分配内存可能比使用malloc()分配内存,然后在单独的步骤中将它们清零更快,特别是如果在malloc()情况下您通过循环逐个迭代元素来将其清零。 malloc()后跟memset()可能与calloc()速度大致相同。
如果您不关心实际存储计算结果之前数组元素是垃圾数据,则在malloc()后没有必要初始化数组。

我正在使用C语言。我认为memset()函数是用于C++的,而在C语言中不可用。 - yCalleecharan
15
我不敢断言malloc/memset序列与calloc一样快。这取决于libc的实现方式。如果OS提供的内存已经初始化为零,那么calloc实现可能会知道这一点,从而跳过对内存的清零操作。在malloc/memset序列中使用memset将是多余的,肯定不及calloc快。例如,在Linux下,当请求大块内存且内存已被Linux清零时,会使用mmap()系统调用。 - Fabian
6
@Fabian:在mmap时,内存并没有“已经清零”。相反,它是对通用零页面的未修改写时复制引用。在第一次写入时,它将被实例化为填充了零的物理内存。因此,使用calloc将内存零初始化的成本从分配时间推迟到第一次写入时间。这在实时应用程序中非常有用,其中单个大型memset可能会导致太多的延迟,但在许多后续的本地访问中分摊的成本是可以接受的。 - R.. GitHub STOP HELPING ICE
@R..:有趣,我不知道还有一个通用的零页面。但这仍然意味着calloc比malloc/memset更快。因为在memset的第一次写入时,整个页面将被清零,后续的memset写入是CPU周期/内存带宽的浪费。或者我错过了什么? - Fabian
使用calloc分配内存在我的系统上更快。https://github.com/dilawar/MyPublic/blob/master/CLike/malloc_calloc.c - Dilawar
显示剩余6条评论

2

对于1和2,两者都有相同的功能:分配并清零数组,然后使用这些数组。

对于3,如果您不需要先清零数组,则清零是不必要的,而且不进行清零操作会更快。

虽然calloc的清零操作可能比您编写的代码更高效,但与程序执行其他工作相比,这种差异很小。calloc的真正优点在于无需自己编写代码,从而节省时间。


1

你在第三点中提到的观点似乎表明了一个不必要的初始化或情况。从速度上来说,这是非常糟糕的,不仅浪费了执行它所花费的时间,而且由于它而发生了大量的缓存驱逐。

使用memset()bzero()(它们都会被calloc()调用)是使您的缓存失效的好方法。除非您确定不会覆盖所有内容但可以读取尚未写入的缓冲区部分(如果0是可接受的默认值),否则不要这样做。如果您无论如何都要覆盖所有内容,请不要不必要地初始化内存。

不必要的内存写入不仅会破坏您的应用程序性能,还会破坏与其共享同一CPU的所有应用程序的性能。


感谢您的有趣输入。 - yCalleecharan

0

callocmemset方法应该差不多,甚至比自己清零稍微快一些。

无论如何,这都与您在主循环内执行的操作相关,这可能是数量级更大的。


谢谢。循环内部的操作可能会非常耗时。 - yCalleecharan

0

malloc比Calloc更快的原因是,malloc直接从操作系统返回内存。但是当您调用Calloc时,它会从内核或操作系统获取内存,并将其初始化为零,然后再返回给您。因此,初始化需要时间。这就是为什么malloc比Calloc更快的原因。


0

我不知道对于Linux。但在Windows上有一种称为“零页线程”的东西... calloc使用那些已经初始化为零的页面。在malloc和calloc之间没有速度差异。


-8

malloccalloc有两个不同之处:

  1. malloc只需要一个参数,而calloc需要两个参数。

  2. malloccalloc更快,原因是malloc将单维数组处理为指针格式,而calloc将双维数组处理为单维数组,然后再转换为指针格式。

我认为这就是为什么malloccalloc处理速度更快的原因。


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