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

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

#include  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 

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

(C99,7.20.3.4p2)“realloc函数解除分配ptr指向的旧对象,并返回指向大小指定大小的新对象的指针。”

是的 – 如果成功的话。

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

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

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

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

如果你使用常见的(危险的)成语,情况会更糟:

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

如果对realloc的调用失败,则a将为null并且其原始内存将被孤立,使其在程序退出之前无可挽回地丢失。

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

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

它也有可能

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

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

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

还要记住,这个描述是在实现级别:从语义realloc() ,只要分配没有失败, realloc()总是释放对象。

realloc函数具有以下合同:

void * result = realloc(ptr,new_size)

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

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

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