C动态分配速度问题

时间:2011-09-12 16:23:21

标签: c arrays performance dynamic malloc

我正在使用此代码动态创建二维数组:

char **FileTables;
int rows = 1000;
int i;

FileTables = (char**)malloc(rows * sizeof(char));
for (i = 0; i < rows; i++) {
    FileTables[i] = (char*)malloc(256 * sizeof(char));
}

问题是1000行,可能会有更多,分配所有内存需要几秒钟。 这样做有更快/更好的方法吗?

编辑: 除了明显更简单的代码之外,使用这些方法之一是否有优势?

char **FileTables;
int rows = 1000;
int i;

FileTables = malloc(rows * sizeof(char*));
FileTables[0] = malloc(rows * 256 * sizeof(char));
for (i = 0; i < rows; i++) {
    FileTables[i] = FileTables[0] + i * 256;
}

和..

char (*FileTables)[256];
int rows = 1000;

FileTables = malloc(rows * sizeof(*FileTables));

(是的,我修复了不必要的演员)

7 个答案:

答案 0 :(得分:6)

你可以通过两个分配和一些指针算法来逃避:

int rows = 1000;
int cols = 256;
char *data;
char **FileTables;
int i;

data = malloc(rows * cols);
FileTables = malloc(rows * sizeof(char*));
for (i = 0; i < rows; i++) {
    FileTables[i] = data + i * cols;
}

另请注意,我修复了malloc(rows * sizeof(char))中的错误(sizeof(char)应为sizeof(char*),因为您要将指针数组分配给{{ 1}})。

答案 1 :(得分:4)

只要列数不变,或者你使用的是C99,就可以自行使用单malloc而无需自己进行丑陋的行/列寻址算法:

char (*FileTables)[256] = malloc(rows * sizeof *FileTables);

答案 2 :(得分:3)

如果数组的大小始终为row×256,那么您可以考虑使用一维数组malloc(row * 256),然后大步访问它:

char get(unsigned i, unsigned j, char * array) { return array[j + 256 * i]; }
void set(char value, unsigned i, unsigned j, char * array) { array[j + 256 * i] = value; }

这可以避免多次分配并提供更好的内存局部性。最重要的是,您可以选择行或列排序进行微优化。

答案 3 :(得分:1)

char **FileTables; 
int rows = 1000; 
int i; 

FileTables = (char**)malloc(rows * sizeof(char *)); 
char *data = (char *)malloc(256 * 1000 * sizeof(char));
for (i = 0; i < rows; ++i) { 
    FileTables[i] = data;
    data += 256 * sizeof(char);
}

应该是更好的解决方案。

答案 4 :(得分:1)

我不相信你会在几秒钟内到达。在我的机器上,将行数增加到1000万仍然不到一秒。

但是,如果您想最小化分配,则只需要一个。

FileTables = (char**) malloc(rows * (sizeof(char *) + 256*sizeof(char)));
FileTables[0] = (char *) &FileTables[rows];
for (i = 1; i < rows; i++) {
    FileTables[i] = FileTables[i-1] + 256 * sizeof (char);
}
free(FileTables);

更有效的方法是避免第二级间接。

typedef char chars[256];

int main(int argc, char** argv) {
    chars* FileTables;
    int rows = 100000000;
    int i;

    FileTables = (chars*) malloc(rows * sizeof (chars));
    free(FileTables);

    return (EXIT_SUCCESS);
}

这可以避免指针查找,因为C可以计算其余部分。

答案 5 :(得分:0)

首先,你确定内存分配是问题吗?分配1000块内存一般不需要几秒钟。

如果您有特殊需求,可以查看备用malloc实现(例如,如果您在线程中分配内存,请使用google的tcmalloc)。

否则,malloc的真正“慢”部分实际上是从OS获取内存(使用sbrk()或mmap()),并且大多数malloc实现将一次抓取一大块并以较小的块返回,所以这里没有1000个呼叫分配1k,可能有60个呼叫分配16k。在strace或类似程序下运行程序可能会让你知道实际上正在进行多少个慢速系统调用。你可以自己实现类似的行为,通过一次调用来分配256K并将其细分为更小的块。您可以尝试分配一大块内存,然后立即释放() - 并希望库malloc保留在该内存中,并且不会再返回操作系统。

答案 6 :(得分:0)

这看起来真的不成熟;因为,你要求更快,但你没有表明速度有多快。不过,如果你真的需要这样做......

加快分配的提示:

  1. 执行更少的分配
  2. 执行较小的分配
  3. 正如您所看到的,如果您需要分配10M,这些提示很快就会发生冲突。要确定较小和较少分配之间的正确平衡,需要进行分析。

    查看内存块大小并一次分配整页内存。这是一个旧的硬件黑客,但它确保你不会一次要求多页连续内存(这加快了从免费页面列表中的选择),它也保证你不浪费一些周期地址请求存储器管理器的块保留子系统已经保留的地址。

    如果这不能提供您所需的性能,那么将代码重写为不需要按照它的呈现方式进行分配。

    无论如何,如果没有详细了解计算机上的内存管理子系统是如何实际设计的,那么就无法保证最佳的分配速度。