我可以假设用较小的大小调用realloc可以释放余数吗?

时间:2012-03-05 22:36:53

标签: c malloc free realloc

让我们考虑一下非常简短的代码片段:

#include <stdlib.h>

int main()
{
    char* a = malloc(20000);
    char* b = realloc(a, 5);

    free(b);
    return 0;
}

在阅读realloc的手册页后,我不完全确定第二行会导致释放19995个额外字节。引用手册页:The realloc() function changes the size of the memory block pointed to by ptr to size bytes.,但根据该定义,我可以确定其余的将被释放吗?

我的意思是,b指向的块肯定包含5个空闲字节,所以对于懒惰的顺从分配器是否足以为realloc线做任何事情都不够?

注意:我使用的分配器似乎释放了19 995个额外字节,如valgrind在注释free(b)行时所示:

==4457== HEAP SUMMARY:
==4457==     in use at exit: 5 bytes in 1 blocks
==4457==   total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated

5 个答案:

答案 0 :(得分:24)

是的,如果可以分配新对象,则由C标准保证。

  

(C99,7.20.3.4p2)“realloc函数释放ptr指向的旧对象,并返回一个指向大小指定大小的新对象的指针。”

答案 1 :(得分:19)

是的 - 如果成功的话。

您的代码段显示了一个众所周知的恶意错误:

char* b = (char*) realloc(a, 5);

如果成功,将释放先前分配给a的内存,b将指向可能与原始块重叠或不重叠的5个字节的内存。

但是,如果通话失败,b将为null,但a仍将指向其原始内存,该内存仍然有效。在这种情况下,您需要free(a)才能释放内存。

如果你使用常见的(危险的)习语,那就更糟了:

a = realloc(a, NEW_SIZE);     // Don't do this!

如果对realloc的调用失败,则a将为null,其原始内存将被孤立,使其无法恢复,直到您的程序退出。

答案 2 :(得分:3)

这取决于你的libc实现。以下所有内容都符合以下行为:

  • 什么也不做,即让数据保持原样并返回旧块,可能重新使用现在未使用的字节进行进一步分配(afaik这种重用并不常见)
  • 将数据复制到新块并将旧数据释放回操作系统
  • 将数据复制到新块并保留旧数据以进行进一步分配

也可以

  • 如果无法分配新块,则返回空指针

在这种情况下,旧数据也将保持原样,这可能导致内存泄漏,例如,如果realloc()的返回值覆盖指向该块的指针的唯一副本。

合理的libc实现将使用一些启发式方法来确定哪种解决方案最有效。

另请注意,此描述处于实现级别:从语义上讲,只要分配没有失败,realloc()就会释放对象。

答案 3 :(得分:1)

realloc函数具有以下合同:

void * result = realloc(ptr,new_size)

  • 如果结果为NULL,则ptr仍然有效且不变。
  • 如果结果为非NULL,则ptr现在无效(就像它已被释放一样),并且不能再次使用。结果现在是一个指向new_size字节数据的指针。

引擎盖下的内容的具体细节是特定于实现的 - 例如结果可能等于ptr(但不能再触及new_size之外的额外空间)并且realloc可以自由调用,或者可以自己执行内部操作自由代表。关键是作为开发人员,如果realloc返回非null,则不再对ptr负责,并且如果realloc返回NULL,则仍然对此负责。

答案 4 :(得分:0)

似乎不太可能释放19995个字节。 更有可能的是,realloc用另外的5字节块替换了20000字节的块, 也就是说,释放了20000字节的块,并分配了一个新的5字节块。