如果malloc
分配失败,我们应该再试一次吗?
在这样的事情中:
char* mystrdup(const char *s)
{
char *ab = NULL;
while(ab == NULL) {
ab=(char*)malloc(strlen(s)+1);
}
strcpy(ab, s);
return ab;
}
while循环是否对检查内存分配有效?
答案 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;
}