【问题标题】:Fastest way possible to allocate an array of strings分配字符串数组的最快方法
【发布时间】:2011-10-06 17:04:31
【问题描述】:

我有一个函数,它需要一个字符串数组(buffer)并且需要增加它的大小。 所以我调用了一个 realloc

temp = (char**) realloc (buffer, newSize * (sizeof(char*)));
if (temp == NULL)
    return false;
else
    buffer = temp;

到目前为止,一切都很好。现在,对于每个新单元格,我必须调用具有正确大小的 malloc。请注意,newSize 始终是偶数,并且奇数字符串的长度与偶数字符串的长度不同。

for (i = oldSize; i < newSize; i++){
    support = (char*) malloc (LENGTH1 * sizeof(char));
    if (support == NULL){
        marker = i;
        failedMalloc = true;
        break;
    }
    else
        buffer[i] = support;

    i++;

    support = (char*) malloc (LENGTH2 * sizeof(char));
    if (support == NULL){
        marker = i;
        failedMalloc = true;
        break;
    }
    else
        buffer[i] = support;

}

事实是,由于我迟早会处理大量数据,因此我将完成内存,而 realloc 或其中一个 malloc 将失败。问题是,如果它是失败的 malloc 之一,那么我将不得不调用 数百万 的 free 来清理一些内存。这需要很多时间。有什么方法可以加快这个过程,甚至更好地避免它?

if (failedMalloc){
    for (i = oldRows; i < marker; i++)
        free(buffer[i]);
    temp = (char**) realloc (buffer, oldRows * (sizeof(char*)));
}

PS:是的,我知道指针运算比数组索引更快。当我找到解决这个问题的方法时,我会实现它,目前我更喜欢使用数组索引,因为我找到了不易出错。但最终版本会使用指针算法

【问题讨论】:

  • 指针算法并不比数组索引快
  • @sth,我在我的基准测试中发现了同样的事情——x86 架构在指令级内置了索引,所以如果你无论如何都要循环索引,你可以免费获得它.

标签: c arrays performance resize realloc


【解决方案1】:

不要单独分配每个字符串,而是按块分配它们。例如,您可以 malloc 128*(LENGTH1+LENGTH2) 并为 256 个连续字符串留出空间。每当您的索引越过块边界时,malloc 另一个大块并使用模算术来获取字符串开头的偏移量。

附: sizeof(char) 保证为 1。

【讨论】:

  • 该概念的变体:malloc((newSize / 2) * (LENGTH1 + LENGTH2) + (newSize & 1 ? LENGTH1 : 0));
  • 只需要记住在这种情况下不要单独释放每个字符串......只是每个字符串块,当块中的字符串不再需要时。此外,如果他在这样的循环中填充各个字符串的地址,如果他愿意的话,他可以很容易地使用指针运算而不是模运算来获取它们的地址。
  • 你能给我一个小的示例源代码吗?我不确定我是否理解您的建议。尤其是我不明白如何访问这些字符串块,因为我尝试过的内容崩溃了。另外,我不知道这是否重要,但我不能使用 malloc(),我必须 realloc() 因为我正在增加一个已经存在的数组
  • @Alex 保留realloc 部分...但是在分配新字符串时,为 256 分配足够的空间(但仅在 i % 256 == 0 时)。然后在您填写buffer 数组时,将适当的偏移量添加到该malloced 地址。
【解决方案2】:

分配更大的内存块。 malloc 调用越少越好。最快的方法是预先计算所需的大小并只分配一次。

另外,在这里使用指针算法不会产生任何明显的差异。

【讨论】:

    【解决方案3】:

    您可以编写自己的分配和释放例程,并使用它们而不是malloc/free 来处理字符串。如果您的例程 malloc 有一个或多个大缓冲区并分出一小部分,那么您只需在每个大缓冲区上调用 free 即可一次性释放全部。

    在所有分配的大小都相同的情况下,总体思路尤其适用,在这种情况下,它被称为“池分配器”。在这种情况下,对于每个数组或字符串,您可以为LENGTH1 分配一个关联的池,为LENGTH2 分配另一个池。

    我说,“自己写”,但毫无疑问,有一些简单的开源池分配器可供使用。

    【讨论】:

      【解决方案4】:

      避免浪费内存的一种方法是每次malloc更大的内存,当你需要malloc时,

      malloc 固定大小(对齐到 2^n),例如

      int m_size = 1;
      
      // when need malloc
      while (m_size < require_size) m_size * 2;
      malloc(m_size);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-20
        相关资源
        最近更新 更多