如果没有连续的内存空间,realloc会怎么做?

13

realloc 用于动态重新分配内存。

假设我使用 malloc 函数分配了 7 个字节,现在我想将其扩展为 30 个字节。

如果内存中没有连续的 30 个字节的空间,后台会发生什么情况?

会出现错误还是内存会被分配成多个部分?

5个回答

13

realloc的实现大致如下:

  • 如果当前块后面有足够的空闲空间来满足请求,则扩展当前块并返回指向该块开头的指针。
  • 否则,如果其他地方有足够大的空闲块,则分配该块,复制旧块中的数据,释放旧块,并返回指向新块开头的指针。
  • 否则,通过返回NULL来报告失败。

因此,您可以通过测试NULL来检测失败,但要注意不要过早地覆盖旧指针:

int* p = malloc(x);
/* ... */
p = realloc(p, y); /* WRONG: Old pointer lost if realloc fails: memory leak! */
/* Correct way: */
{
  int* temp = realloc(p, y);
  if (NULL == temp)
  {
    /* Handle error; p is still valid */
  }
  else
  {
    /* p now possibly points to deallocated memory. Overwrite it with the pointer
       to the new block, to start using that */
    p = temp;
  }
}

这个 realloc 函数适用于所有实现吗? - Spikatrix
@CoolGuy:有些实现可能无法执行扩展当前块的第一步,但除此之外,这就是所有实现中realloc的可观察行为。 - Bart van Ingen Schenau

7

realloc只有在能够返回连续的内存块时才会成功。如果不存在这样的内存块,它将返回NULL


4
@Mark - 原始内存不会改变。在这种情况下的常见错误是 'x = realloc(x)',你必须执行 'newX = realloc(x)' 以避免在出现错误时泄漏原始的 x。 - Steve Townsend
@Steve Townsend - 这只有在失败时才会发生,对吧?当成功时,它会释放原始指针。而这个页面上的Mark是谁?O_o - Praveen S
我猜可能出现了错误。第一条评论是由用户sharptooth发布的,但现在已更改,尽管两者都是针对Mark的。那是一个bug吗?:-P - Praveen S
@Praveen - 我的评论是针对一个已被删除的早期评论的。是的,我展示的用法仍然存在 bug。当成功时,它会释放原始指针(或者如果可以在那里锚定更大的连续块,则将其返回给您以供再次使用)。 - Steve Townsend
@Steve:如果你在后面加上 if (!x) exit(1);,那么这就不是一个 bug 了 :-) - R.. GitHub STOP HELPING ICE
@R - 很好的观点。在许多应用程序中,我相信内存分配失败将意味着即将死亡。 - Steve Townsend

1

来自man page

realloc()返回指向新分配的内存的指针,该内存适合任何类型的变量并且可能与ptr不同,如果请求失败则为NULL。

换句话说,要检测失败,只需检查结果是否为NULL。

编辑:如评论中所述,如果调用失败,则原始内存不会被释放。


2
值得注意的是,从man页面中可以看出:如果realloc()失败,则原始块保持不变;它不会被释放或移动。 - Mark Elliot

1

一般而言,这取决于实现方式。在x86(-64) Linux上,我相信标准的doug lea malloc算法将始终分配至少一个标准的x86页面(4096字节),因此对于您上述描述的情况,它只会重置边界以适应额外的字节。当涉及到将7字节的缓冲区重新分配为PAGE_SIZE+1时,我相信它将尝试分配下一个连续的页面(如果有的话)。

如果您正在Linux上开发,请阅读以下内容:

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. This is a really bad bug. In case it turns out that the system is out of memory, one or more processes will be killed by the infamous OOM killer. In case Linux is employed under circumstances where it would be less desirable to suddenly lose some randomly picked processes, and moreover the kernel version is sufficiently recent, one can switch off this overcommitting behavior using a command like:

# echo 2 > /proc/sys/vm/overcommit_memory

See also the kernel Documentation directory, files vm/overcommit-accounting and sysctl/vm.txt.


0

FreeBSD和Mac OS X都有reallocf()函数,当请求的内存无法分配时,该函数将释放传递的指针(请参阅man realloc)。


如果你真的想要这种行为,与其使用它,编写自己的函数会更有意义。但我无法想象它有多么有用 - 这是在丢弃可能有价值的数据。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接