C语言循环中的内存分配成本

The cost of memory allocation in a loop in C

在时间成本方面,在循环内部或外部分配数组是否有显着差异?

我在程序的一个循环内的函数中使用了很多数组,我是否应该将所有数组作为函数参数传递以提高性能,尽管它会降低可读性?例如:

#include <stdlib.h>
#define N 1000000
void foo()
{
    int* array = (int*)malloc(N*sizeof(int));
    /*
    Do something with the array
    */
    free(array);
}
int main()
{
    int i;
    for(i=0; i<1000000; i++)
        foo();
    return 0;
}

#include <stdlib.h>
#define N 1000000
void foo(int* array)
{
    /*
    Do something with the array
    */
}
int main()
{
    int i;
    int* array = (int*)malloc(N*sizeof(int));
    for(i=0; i<1000000; i++)
        foo(array);
    free(array);
    return 0;
}

第二个例子在时间上更好。假设您对每个示例 'foo' 中的数组所做的事情是相同的。

在第二个例子中:你分配了一个数组,然后对它做了很多次。然后在你这样做之后摧毁它。

在第一个示例中:循环的每次迭代都会创建一个新数组,执行某些操作然后销毁它。这意味着每次循环迭代都会花费额外的时间来创建和销毁数组。

内存分配的成本不是很依赖分配的大小。粗略地说,任何大小的内存分配都是 O(1),显然标准库已优化以尽可能快地进行分配。

所以如果你需要一个非常大的分配,就像在示例程序中那样,与初始化分配内存的成本相比,分配的成本将是微不足道的(更不用说实际进行计算的成本了必需的)。

对于非常紧凑的循环中的小分配,分配开销可能很明显,替代机制可能会有用;其中之一是问题中建议的,将预分配的数组作为附加参数传递给函数。 (其他可能性包括使用 C 的可变长度数组 (VLA),如果它们在所有目标平台上都可用,或者 alloca/_alloca/_malloca。)

但我建议在有确凿证据证明节省时间是合理的之前不要实施这种形式的微优化;否则,可维护性和可读性方面的成本将超过您可能节省的任何时间。

我觉得声明数组然后使用它是更好的做事方式。

您的声明发生在更高级别的代码主体中并且只发生一次:因此很容易理解正在发生的事情、更改分配大小、处理分配错误和调试。

在 for 循环中声明数组对我来说是一个明确的 code smell:这是一个缺乏模块化的解决方案。