如果malloc失败怎么办?

时间:2012-08-03 03:23:28

标签: c memory malloc

如果malloc分配失败,我们应该再试一次吗?

在这样的事情中:

char* mystrdup(const char *s)  
{
    char *ab = NULL;

    while(ab == NULL) {
        ab=(char*)malloc(strlen(s)+1);  
    }

    strcpy(ab, s);
    return ab;
}

while循环是否对检查内存分配有效?

10 个答案:

答案 0 :(得分:27)

一般情况下,现代malloc()实现只会作为绝对的最后手段返回NULL,再次尝试肯定无济于事。唯一有用的是释放一些内存然后再试一次。如果你的应用程序拥有任何可消耗的资源,那么这将是释放它们的时间,然后再给它一次。

在某些环境中,一种有用的做法是将少量内存分配为雨天基金。如果malloc() 返回NULL,您可以释放该下雨天的资金,然后分配您需要的任何资源来处理错误并优雅地退出。使用旧的Macintosh Toolbox编程时,这是一种常见的做法;如果malloc()返回NULL,您可以使用该空格创建一个对话框,以便在退出前报告问题。

答案 1 :(得分:8)

在单线程程序中“再次尝试”而不会在尝试之间释放任何内存,这没有任何实际意义。它将永远循环。

在多线程程序中,如果另一个并行运行的线程突然决定释放一些自己的内存,这可能会“正常”。在这种情况下的循环将构成经典的“忙碌等待”循环。但即使在这种情况下,这些代码的实际价值也很少,原因多于一个。

答案 2 :(得分:3)

不,永远不会。如果malloc返回NULL,则表示错误,您可能应该中止。

答案 3 :(得分:2)

在没有争论为什么或什么时候这会有用的情况下,尝试在循环中重新分配可能会起作用,至少在具有64位代码的Windows和默认页面文件设置上。此外,这可能会出乎意料地购买更多额外的虚拟内存。虽然,不要在无限循环中执行此操作,而是使用有限数量的重试。作为证明,请尝试以下代码模拟泄漏1 Mb的内存。您必须在Release版本中运行它,最好不要在调试器下运行。

for (int i = 0; i < 10; i++)
{
  size_t allocated = 0;
  while (1)
  {
    void* p = malloc(1024 * 1024);
    if (!p)
      break;

    allocated += 1;
  }

  //This prints only after malloc had failed.
  std::cout << "Allocated: " << allocated << " Mb\n";
  //Sleep(1000);
}

在我的具有8 Gb RAM和系统管理页面文件的计算机上,我得到以下输出(使用VS2013 for x64 target构建,在Windows 7 Pro上测试):

Allocated: 14075 Mb
Allocated: 16 Mb
Allocated: 2392 Mb
Allocated: 3 Mb
Allocated: 2791 Mb
Allocated: 16 Mb
Allocated: 3172 Mb
Allocated: 16 Mb
Allocated: 3651 Mb
Allocated: 15 Mb

我不知道这种行为的确切原因,但是一旦页面文件调整大小无法跟上请求,似乎分配开始失败。 在我的机器上,页面文件在此循环后从8 gb增长到20 Gb(在程序退出后降回到8 Gb)。

答案 4 :(得分:0)

这绝对不可能做到你想做的事情;如果你内存不足,忙碌循环直到你获得更多可能会令人失望。您应该只将NULL返回给调用程序,以便它可以通过释放不再需要的内存或返回错误来处理资源耗尽。

答案 5 :(得分:0)

malloc()尽力分配内存。如果它失败了,而不是重新尝试在while循环中分配内存(程序可能永远卡在那里),尝试释放一些其他进程或线程持有的内存,如果可以,然后重试。

另一种选择是增加内存,通过增加交换文件或分页内存,在代码本身内增加交换文件或分页内存(但危险且不可取)或手动执行。

避免此类问题的最佳方法是在编写代码时计算或估计内存需求。

答案 6 :(得分:0)

尝试增加堆大小(为动态分配留出的内存)。

答案 7 :(得分:0)

这取决于您所使用的软件以及受影响的代码部分。

首先要知道,当没有可用页面时,malloc()可能会失败,如果您的应用程序达到了限制,那么它将无法进行任何循环,但是如果系统内存不足,则值得尝试,但是您必须避免任何无限循环。惊喜!如果操作系统临时响应而无法分配更多的RAM,那完全正常,那么您可以按照自己的方式进行处理。

这还是一个很好的问题

类似的问题不是捕获信号,并且当多线程或异步TCP服务器获得异常终止的客户端连接时,该软件被SIGPIPE终止。这是正常现象,但是会导致程序结束,但不应结束。为了防止这种情况,您必须钩住信号。

在真实的例子中(我自己的)。

当malloc失败并且仅部分影响我的代码时

当新连接发送数据时,我曾经使用过malloc()或new [],我将接收到的数据存储到缓冲区中,如果malloc或realloc失败,则函数返回false并释放缓冲区,连接因错误而掉线(内衣)因此,在这种情况下,软件将继续运行,但一个连接断开。我认为这是正确的方法。

何时malloc必须导致软件中止

我曾经使用malloc()为关键数据(如数组,定义核心的结构)腾出空间,这通常在软件开始时作为init节运行,如果malloc()失败,则软件必须中止并返回错误代码,因为所有操作取决于必须填充数据的表。 (内置文件系统)

malloc能够重试

我有一些行业领先的数据记录器软件(高可用性),如果malloc()失败,我会触发一个mutex_lock(),这会导致软件在后端冻结,并尝试重试X秒钟的malloc过程。如果malloc()继续失败,则软件将开始在所有线程上调用析构函数并执行完全关闭操作,但此时试图malloc()不成功的线程除外,有两种选择,malloc()成功并完成堆栈调用,以及退出最后一个线程或执行回滚并退出最后一个线程。

无论何时发生该软件也无法退出,请尝试从头开始,依此类推。

也许值得一提。.

几年前我遇到了完全相同的难题,是什么原因导致软件内存泄漏并吞噬了我所有的RAM,但是要保存当前状态,我必须将其写出,这是在多次malloc()之后完成的,解决方案是发生这种情况时,我关闭了所有线程并调用了析构函数并保存了数据,但是有趣的是,当我关闭所有连接并释放套接字ssl_ctx时,...经过几天的快乐调试,内存消耗降至128KB,我发现了这一点SSL_CTX具有内部存储和缓存。因此,现在当没有在线连接时,我会释放SSL_CTX并像魅力一样工作。

SUMM

因此,如您所见,这是一门艺术,您可以使用malloc()来完成您想做的事情,而这一切取决于您,没有书,也没有标准,如果malloc()失败了该怎么办。如果有人告诉您您应该做什么,仅是他的意见。

避免无限循环的首选方式

PSEUDO CODE:

var ts = TIME()
var max_seconds = 5
var success = true

WHILE (MALLOC() == FAIL) DO
   IF TS + max_seconds < TIME() THEN
      success = false
      BREAK
   END
   SLEEP(100ms)
END


答案 8 :(得分:0)

根据我的经验(UNIX),在网络管理员吹嘘“您想要的新服务器已经准备就绪并且可以使用”之后,立即可靠地处理malloc故障非常重要。一个典型的答复是:“哇,太快了,谢谢”。这时malloc将返回NULL。

最好的办法是抛出一个std :: bad_alloc异常,并带有一条静态错误消息,该消息会被捕获并显示在main()中。希望您的析构函数进行足够的清理以释放内存,以使main中的错误处理不会失败。

如果使用合理的操作系统和编程风格,则OOM条件可以恢复。

答案 9 :(得分:-1)

您没有正确分配内存malloc函数require参数作为它需要分配的字节数,但是您正在传递字符串的长度,因此malloc将根据长度而不是字符串所使用的字节来保留内存。您应该改用sizeof(),如果仍然失败,则malloc返回null,这表示堆栈中没有足够的内存来满足您的要求。 要正确运行代码,请尝试以下操作:-

char * mystrdup(const char * s)
{ char * ab = NULL;

while(ab == NULL) {
    ab=(char*)malloc(sizeof(s));  
}

strcpy(ab, s);
return ab;

}