【问题标题】:Realloc Using Way too much MemoryRealloc 使用太多内存
【发布时间】:2015-06-18 23:11:24
【问题描述】:

我已经做了一个简单的例子,说明如何使用 realloc 将元素添加到数组中。这将在具有更多元素的未来计划中得到扩展。

#include <stdio.h>//printf
#include <stdlib.h>//malloc, realloc

int main() {
//BEGIN REALLOCATE-ABLE ARRAY
    unsigned int *array, loop_variable;
    const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99;
    array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
        array[loop_variable] = loop_variable;
    }
//BEGIN REALLOCATION
    for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
        array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
        array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
        printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
    }
//BEGIN PRINTING ARRAY VALUES
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
        printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
    }
//BEGIN FREE ARRAY
    free(array); array = NULL;
    return 0;
}

这应该可以在任何带有 gcc 或 clang 的计算机上编译。然后我在 valgrind 上运行这个程序以确保没有内存泄漏,我得到了这个:

==10791== HEAP SUMMARY:
==10791==     in use at exit: 0 bytes in 0 blocks
==10791==   total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated
==10791== 
==10791== All heap blocks were freed -- no leaks are possible
==10791== 
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

但是,让我感到困扰的是,我使用 20,988 字节来存储 101 个元素的数组。随着数组变大,内存使用呈指数增长,而不是线性增长 4 字节/元素。

如果我正确理解 Valgrind 的输出,这个数组应该有 4*101 个元素 = 404 字节的内存大小,但 似乎使用了大约 50 倍的内存正如它应该。对于这么小的程序来说这是一个小问题,但是更有意义的程序会在这台计算机上耗尽内存。

我的问题:这个数组真的使用了 20,988 字节,还是 Valgrind 重复计算了内存?

有没有更节省内存的方法来做到这一点?我无法理解 realloc 的其他示例,尽管我已尝试尽可能密切关注它们并使这个问题与尽可能多的用户相关。

【问题讨论】:

  • Valgrind 不是将mallocrealloc 参数中的总大小报告为total heap usage,而忽略所有frees?
  • 你确定它是呈指数增长,而不是 O(n^2)? 20988 非常接近 4*101*101/2。
  • 始终检查 (!=NULL) 从 malloc 和函数族返回的值,以确保操作成功。
  • 使用 realloc() 时。将返回值分配给临时指针。测试 temp 指针是否为 NULL,(如果为 NULL,则处理错误,否则分配 array = temp 指针。否则,如果 realloc 失败,则数组中的当前指针丢失,导致内存泄漏
  • 最终的 realloc 循环是:realloc( 4*(4+98) ) I.E. 400字节。既然最终大小是已知的,为什么要循环? malloc 和 realloc 是“昂贵的”,建议只有一个 malloc 的最终大小,然后是一个循环来设置分配内存的内容。

标签: c arrays memory valgrind realloc


【解决方案1】:
==10791==     in use at exit: 0 bytes in 0 blocks
==10791==   total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated

这个数组真的使用了 20,988 个字节吗

不,它使用 0 个字节。

“已分配”显然意味着“已分配”,包括已释放的字节,因为“仍然分配”的内存量为零(另一行告诉您)。

【讨论】:

  • 程序“永远分配”了 100 次 4 字节。所有 [re-]allocation 请求的总数为 20,200 字节(即:4+(4+4)+(4+(4+4))+...)。仍然缺少 788 个字节 - 也许这是开销?
  • @PaulOgilvie 通过在 Valgrind 下执行程序,您要求它在realloc 总是创建一个新块并释放旧块的环境中运行,因为这样就找到了调用realloc后使用旧指针的编程错误。我不使用 Valgrind,因为我在自己的类似系统上工作,但这就是我的系统的工作方式,如果 Valgrind 的系统也不以这种方式工作,我会感到惊讶。此外,既然我们已经确定“堆使用情况”只是使用不寻常的算法计算的统计量,那么我们在争论什么?
  • @PaulOgilvie:由于对齐限制,malloc()realloc() 有效地以谨慎的大小返回内存,在我查看的每个 x86 实现中,内存始终是 8 字节的倍数。对 Valgrind 源代码的检查可能表明它正在计算这些块中分配的内存量。这将解释您注意到的一些差异。
【解决方案2】:

感谢用户 Pascal Cuoq,答案是 Valgrind 将对每个分配的内存分配求和。这就是为什么我很困惑,并认为 realloc 使用了太多内存。

我想如果你想找到数组的大小,你可以注释掉上面写着的那一行

free(array); array = NULL;

故意引入内存错误,Valgrind 会输出

==11699== LEAK SUMMARY:
==11699==    definitely lost: 408 bytes in 1 blocks
==11699==    indirectly lost: 0 bytes in 0 blocks
==11699==      possibly lost: 0 bytes in 0 blocks
==11699==    still reachable: 0 bytes in 0 blocks
==11699==         suppressed: 0 bytes in 0 blocks
==11699== 
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

它会在最后一次迭代中为您提供数组的真实大小。可能有更好的方法来做到这一点,但我的观点是正确的。

我在这里添加了其他用户建议的改进。我很难在搜索引擎上找到良好的、最小的 realloc 工作示例,并且为了将来在搜索引擎上找到它的任何人使用,这是一个很好但可能不是最好的如何使用的非常基本的最小工作示例在 C 中重新分配:

#include <stdio.h>//include printf function
#include <stdlib.h>//include malloc, realloc functions

int main() {
/*BEGIN REALLOCATE-ABLE ARRAY*/
    unsigned int *array, loop_variable;
    const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99999;
    array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
        array[loop_variable] = loop_variable;
    }
/*BEGIN REALLOCATION*/
    for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
        array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
        if (array == NULL) {
            printf("Array variable %d failed to reallocate :,-(\n",loop_variable);
            exit(EXIT_FAILURE);
        }
        array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
        printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
    }
/*BEGIN PRINTING ARRAY VALUES*/
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
        printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
    }
/*BEGIN FREE ARRAY*/
    free(array); array = NULL;
    return 0;
}

【讨论】:

    猜你喜欢
    • 2021-03-26
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多