realloc失败的几率是多少?

use*_*241 9 c memory-management realloc

当它的可用内存耗尽时是否会失败malloc?或者是否有其他原因?

R..*_*R.. 11

任何的分配功能(malloc,realloc,calloc,和POSIX, posix_memalign)可能失败对于任何的下列原因,以及其它可能的:

  • 您已经用完了整个虚拟地址空间,或者至少耗尽了它的可用部分.在32位机器上,只有4GB的地址,可能还有1GB左右的内存供OS内存使用.即使您的计算机具有16GB的物理内存,单个进程也不能使用超过它的地址.
  • 您没有用尽您的虚拟地址空间,但是您已将其碎片严重到没有所请求大小的连续范围的地址可用.如果您成功分配6个512MB块,每隔一个块释放一次,然后尝试分配1GB块,则可能会发生这种情况(在32位计算机上).当然,还有很多其他具有较小内存大小的示例.
  • 您的机器已经耗尽了物理内存,这可能是由于您自己的程序已经全部使用过,或者是机器上运行的其他程序已经使用了所有内存.一些系统(默认配置中的Linux)将过度使用,这意味着malloc在这种情况下不会失败,但是当OS计算出没有足够的物理内存时,操作系统将会杀死一个或多个程序.但是在健壮的系统(包括禁用过度使用的Linux)上,malloc如果没有物理内存,则会失败.

请注意,严格来说,分配函数可以随时以任何理由失败.最小化失败是一个实施质量问题.realloc即使减小对象的大小,也可能会失败; 这可能发生在严格按大小分配分配的实现上.当然,在这种情况下,您可以继续使用旧的(较大的)对象.


zwo*_*wol 5

你应该认为是realloc这样工作的:

void *realloc(void *oldptr, size_t newsize)
{
   size_t oldsize = __extract_size_of_malloc_block(oldptr);
   void *newptr = malloc(newsize);

   if (!newptr)
     return 0;

   if (oldsize > newsize)
     oldsize = newsize;

   memcpy(newptr, oldptr, oldsize);
   free(oldptr);
   return newptr;
}
Run Code Online (Sandbox Code Playgroud)

一个实现可能能够比这更有效地处理特定情况,但完全按照所示工作的实现是 100% 正确的。这意味着realloc(ptr, newsize)可能会失败任何时候malloc(newsize)都会失败;特别是即使您正在缩小分配,它也可能会失败。

现在,在现代桌面系统上,有充分的理由不要尝试从malloc故障中恢复,而是包装malloc在一个函数(通常称为xmalloc)中,如果malloc失败则立即终止程序;自然,同样的论点适用于realloc。案例是:

  1. 桌面系统通常以“过度使用”模式运行,假设程序实际上不会使用所有地址空间,内核会很高兴地分配比 RAM+swap 支持的地址空间更多的地址空间。如果程序确实尝试使用所有这些,它将被强行终止。在这样的系统上, malloc 只有在耗尽地址空间时才会失败,这在 32 位系统上不太可能,而在 64 位系统上几乎不可能。
  2. 即使您没有处于过度使用模式,桌面系统也有可能拥有如此多的 RAM 和交换空间,以至于在您导致malloc失败之前很久,用户就会厌倦他们的磁盘抖动并强行终止您的程序。
  3. 没有实用的方法来测试从分配失败中恢复;即使您有一个可以精确控制哪些调用malloc失败的 shim 库(这些 shim 最多很难创建,最坏情况下不可能创建,具体取决于操作系统),您也必须测试 2 N 个失败模式的顺序,其中 N 是在你的程序中调用 malloc 的次数。

论点 1 和 2 不适用于嵌入式或移动系统(但!)但论点 3 在那里仍然有效。

参数 3 仅适用于必须在每个调用站点检查和传播分配失败的程序。如果您很幸运地使用 C++,因为它打算使用(即有例外),您可以依靠编译器为您创建错误恢复路径,因此测试负担会大大减少。并且在当今值得使用的任何高级语言中,您都有异常和垃圾收集器,这意味着即使您愿意,也不必担心分配失败。


Ear*_*rlz 1

我想说它主要是特定于实现的。有些实施很可能会失败。有些可能会在重新分配之前使程序的其他部分失败。始终保持防御状态并检查是否失败。

并记住释放您尝试重新分配的旧指针。

ptr=realloc(ptr,10);
Run Code Online (Sandbox Code Playgroud)

总是可能存在内存泄漏。

总是这样做:

void *tmp=ptr;
if(ptr=realloc(ptr,10)==NULL){
  free(tmp);
  //handle error...
}
Run Code Online (Sandbox Code Playgroud)