C++ `new` 操作符在现实生活中会抛出异常吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2497151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can the C++ `new` operator ever throw an exception in real life?
提问by osgx
Can the new
operator throw an exception in real life?
new
操作符在现实生活中可以抛出异常吗?
And if so, do I have any options for handling such an exception apart from killing my application?
如果是这样,除了终止我的应用程序之外,我还有其他处理此类异常的选择吗?
Update:
更新:
Do any real-world, new
-heavy applications check for failure and recover when there is no memory?
是否有任何现实世界的重度new
应用程序检查故障并在没有内存时恢复?
See also:
也可以看看:
采纳答案by Brian R. Bondy
The new operator, and new[] operator should throw std::bad_alloc
, but this is not always the case as the behavior can be sometimes overridden.
new 运算符和 new[] 运算符应该 throw std::bad_alloc
,但情况并非总是如此,因为有时会覆盖行为。
One can use std::set_new_handler
and suddenly something entirely different can happen than throwing std::bad_alloc
. Although the standard requires that the user either make memory available, abort, or throw std::bad_alloc
. But of course this may not be the case.
一个人可以使用std::set_new_handler
,突然之间会发生与投掷完全不同的事情std::bad_alloc
。尽管标准要求用户使内存可用、中止或抛出std::bad_alloc
。但当然,情况可能并非如此。
Disclaimer: I am not suggesting to do this.
免责声明:我不建议这样做。
回答by James McNellis
Yes, new
can and will throw if allocation fails. This can happen if you run out of memory or you try to allocate a block of memory too large.
是的,new
如果分配失败,可以并且将会抛出。如果内存不足或尝试分配太大的内存块,就会发生这种情况。
You can catch the std::bad_alloc
exception and handle it appropriately. Sometimes this makes sense, other times (read: most of the time) it doesn't. If, for example, you were trying to allocate a huge buffer but could work with less space, you could try allocating successively smaller blocks.
您可以捕获std::bad_alloc
异常并对其进行适当处理。有时这是有道理的,而其他时候(阅读:大部分时间)则不然。例如,如果您尝试分配一个巨大的缓冲区但可以使用较少的空间,则可以尝试分配连续的较小块。
回答by Permaquid
If you are running on a typical embedded processor running Linux without virtual memory it is quite likely your process will be terminated by the operating system before new fails if you allocate too much memory.
如果您在运行 Linux 的典型嵌入式处理器上运行而没有虚拟内存,那么如果您分配太多内存,您的进程很可能会在 new 失败之前被操作系统终止。
If you are running your program on a machine with less physical memory than the maximum of virtual memory (2 GB on standard Windows) you will find that once you have allocated an amount of memory approximately equal to the available physical memory, further allocations will succeed but will cause paging to disk. This will bog your program down and you might not actually be able to get to the point of exhausting virtual memory. So you might not get an exception thrown.
如果您在物理内存小于最大虚拟内存(标准 Windows 上为 2 GB)的机器上运行程序,您会发现一旦分配了大约等于可用物理内存的内存量,进一步分配就会成功但会导致分页到磁盘。这将使您的程序陷入困境,您实际上可能无法达到耗尽虚拟内存的程度。所以你可能不会抛出异常。
If you have more physical memory than the virtual memory, and you simply keep allocating memory, you will get an exception when you have exhausted virtual memory to the point where you can not allocate the block size you are requesting.
如果您的物理内存比虚拟内存多,并且您只是继续分配内存,那么当您耗尽虚拟内存到无法分配您请求的块大小时,您将收到异常。
If you have a long-running program that allocates and frees in many different block sizes, including small blocks, with a wide variety of lifetimes, the virtual memory may become fragmented to the point where new will be unable to find a large enough block to satisfy a request. Then new will throw an exception. If you happen to have a memory leak that leaks the occasional small block in a random location that will eventually fragment memory to the point where an arbitrarily small block allocation will fail, and an exception will be thrown.
如果你有一个长时间运行的程序,它分配和释放许多不同大小的块,包括小块,具有各种各样的生命周期,虚拟内存可能会变得碎片化,以至于 new 将无法找到足够大的块来满足一个要求。然后 new 会抛出异常。如果你碰巧有内存泄漏,偶尔会泄漏随机位置的小块,最终将内存碎片化到任意小块分配失败的地步,并且会抛出异常。
If you have a program error that accidentally passes a huge array size to new[], new will fail and throw an exception. This can happen for example if the array size is actually some sort of random byte pattern, perhaps derived from uninitialized memory or a corrupted communication stream.
如果你有一个程序错误,意外地将一个巨大的数组大小传递给 new[],new 将失败并抛出异常。例如,如果数组大小实际上是某种随机字节模式,可能来自未初始化的内存或损坏的通信流,就会发生这种情况。
All the above is for the default global new. However, you can replace global new and you can provide class-specific new. These too can throw, and the meaning of that situation depends on how you programmed it. it is usual for new to include a loop that attempts all possible avenues for getting the requested memory. It throws when all those are exhausted. What you do then is up to you.
以上都是针对默认的全局new的。但是,您可以替换 global new,并且可以提供特定于类的 new。这些也可以抛出,这种情况的含义取决于您如何对其进行编程。new 通常包含一个循环,尝试所有可能的途径来获取请求的内存。当所有这些都筋疲力尽时它会抛出。然后你做什么取决于你。
You can catch an exception from new and use the opportunity it provides to document the program state around the time of the exception. You can "dump core". If you have a circular instrumentation buffer allocated at program startup, you can dump it to disk before you terminate the program. The program termination can be graceful, which is an advantage over simply not handling the exception.
您可以从 new 中捕获异常并利用它提供的机会记录异常发生前后的程序状态。您可以“转储核心”。如果在程序启动时分配了循环检测缓冲区,则可以在终止程序之前将其转储到磁盘。程序终止可以是优雅的,这比简单地不处理异常要好。
I have not personally seen an example where additional memory could be obtained after the exception. One possibility however, is the following: Suppose you have a memory allocator that is highly efficient but not good at reclaiming free space. For example, it might be prone to free space fragmentation, in which free blocks are adjacent but not coalesced. You could use an exception from new, caught in a new_handler, to run a compaction procedure for free space before retrying.
我个人还没有看到在异常之后可以获得额外内存的例子。然而,一种可能性如下:假设您有一个高效但不擅长回收可用空间的内存分配器。例如,它可能容易出现空闲空间碎片,其中空闲块相邻但未合并。在重试之前,您可以使用 new_handler 中捕获的 new 异常来运行可用空间的压缩过程。
Serious programs should treat memory as a potentially scarce resource, control its allocation as much as possible, monitor its availability and react appropriately if something seems to have gone dramatically wrong. For example, you could make a case that in any real program there is quite a small upper bound on the size parameter passed to the memory allocator, and anything larger than this should cause some kind of error handling, whether or not the request can be satisfied. You could argue that the rate of memory increase of a long-running program should be monitored, and if it can be reasonably predicted that the program will exhaust available memory in the near future, an orderly restart of the process should be begun.
严肃的程序应该将内存视为一种潜在的稀缺资源,尽可能控制其分配,监控其可用性并在出现严重错误时做出适当的反应。例如,您可以假设在任何实际程序中,传递给内存分配器的 size 参数都有一个很小的上限,并且任何大于这个上限都应该导致某种错误处理,无论请求是否可以使满意。您可能会争辩说,应该监视长时间运行的程序的内存增长速度,如果可以合理地预测该程序将在不久的将来耗尽可用内存,则应该开始有序地重新启动进程。
回答by LeopardSkinPillBoxHat
osgxsaid:
osgx说:
Does any real-world applications checks a lot number of news and can recover when there is no memory?
是否有任何实际应用程序检查大量新闻并且在没有内存时可以恢复?
I have answered this previously in my answerto this question, which is quoted below:
It is very difficult to handle this sort of situation. You may want to return a meaningful error to the user of your application, but if it's a problem caused by lack of memory, you may not even be able to afford the memory to allocate the error message. It's a bit of a catch-22 situation really.
There is a defensive programming technique (sometimes called a memory parachute or rainy day fund) where you allocate a chunk of memory when your application starts. When you then handle the bad_alloc exception, you free this memory up, and use the available memory to close down the application gracefully, including displaying a meaningful error to the user. This is much better than crashing :)
处理这种情况是非常困难的。您可能希望向应用程序的用户返回一个有意义的错误,但如果它是由内存不足引起的问题,您甚至可能无法负担分配错误消息的内存。这确实有点像catch-22的情况。
有一种防御性编程技术(有时称为内存降落伞或雨天基金),您可以在应用程序启动时分配一块内存。当您随后处理 bad_alloc 异常时,您将释放此内存,并使用可用内存正常关闭应用程序,包括向用户显示有意义的错误。这比崩溃要好得多:)
回答by Chris Jester-Young
In Unix systems, it's customary to run long-running processes with memory limits (using ulimit
) so that it doesn't eat up all of a system's memory. If your program hits that limit, you will get std::bad_alloc
.
在 Unix 系统中,习惯上运行具有内存限制的长时间运行的进程(使用ulimit
),这样它就不会占用系统的所有内存。如果您的程序达到该限制,您将获得std::bad_alloc
.
Update for OP's edit: the most typical case of programs recovering from an out-of-memory condition is in garbage-collected systems, which then performs a GC and continues. Though, this sort of on-demand GC is really for last-ditch efforts only; usually, good programs try to GC periodically to reduce stress on the collector.
更新 OP 的编辑:从内存不足情况中恢复的程序最典型的情况是在垃圾收集系统中,然后执行 GC 并继续。不过,这种按需 GC 实际上仅用于最后的努力;通常,好的程序会定期尝试 GC 以减少收集器的压力。
It's less usual for non-GC programs to recover from out-of-memory issues, but for Internet-facing servers, one way to recover is to simply reject the request that's causing the memory to run out with a "temporary" error. ("First in, first served" strategy.)
非 GC 程序从内存不足问题中恢复不太常见,但对于面向 Internet 的服务器,一种恢复方法是简单地拒绝导致内存耗尽并出现“临时”错误的请求。(“先进先得”策略。)
回答by vladr
It depends on the compiler/runtime and on the operator new
that you are using (e.g. certain versions of Visual Studio will not throw out of the box, but would rather return a NULL
pointer a la malloc
instead.)
这取决于编译器/运行时以及operator new
您正在使用的(例如,某些版本的 Visual Studio不会立即使用,而是返回一个NULL
指针 a la malloc
。)
You can always catch
a std::bad_alloc
exception, or explicitly use nothrow new
to return NULL
instead of throwing. (Also see past StackOverflow postsrevolving around the subject.)
你总是catch
可以std::bad_alloc
抛出异常,或者显式地使用nothrow new
返回NULL
而不是抛出。(另请参阅过去围绕该主题的StackOverflow 帖子。)
Note that operator new
, like malloc
, willfail when you have run out of memory, out of address space (e.g. 2-3GB in a 32-bit process depending on the OS), out of quota (ulimit
was already mentioned) or out of contiguous address space (e.g. fragmented heap.)
需要注意的是operator new
,像malloc
,会当你的内存用完了,(在根据操作系统的32位进程如2-3GB)失败了的地址空间,配额外的(ulimit
已经提到)或出连续的地址空间(例如碎片堆。)
回答by moogs
You don't need to handle the exception in every single new
:) Exceptions can propagate. Design your code so that there are certain points in each "module" where that error is handled.
您不需要在每一个中都处理异常new
:) 异常可以传播。设计您的代码,以便在每个“模块”中都有处理该错误的特定点。
回答by squelart
Yes, new
can throw std::bad_alloc
(a subclass of std::exception
), which you may catch.
是的,new
可以抛出std::bad_alloc
( 的子类std::exception
),您可能会抓住它。
If you absolutely want to avoid this exception, and instead are ready to test the result of new
for a null pointer, you may add a nothrow
argument:
如果你绝对想避免这个异常,而是准备好测试new
空指针的结果,你可以添加一个nothrow
参数:
T* p = new (nothrow) T(...);
if (p == 0)
{
// Do something about the bad allocation!
}
else
{
// Here you may use p.
}
回答by sth
Yes new
will throw an exception if there is no more memory available, but that doesn't mean you should wrap every new in a try ... catch
. Only catch the exception if your program can actually do something about it.
new
如果没有更多可用内存,Yes将抛出异常,但这并不意味着您应该将每个 new 包装在try ... catch
. 仅当您的程序实际上可以对其进行处理时才捕获异常。
If the program cannot do anything to handle that exceptional situation, what is often the case if you run out of memory, there is no use in catching the exception. If the only thing you could reasonably do is to abort the program you can as well just let the exception bubble up to top level, where it will terminate the program as well.
如果程序不能做任何事情来处理这种异常情况,如果内存不足,通常情况下,捕获异常是没有用的。如果你唯一能合理做的就是中止程序,你也可以让异常冒泡到顶层,在那里它也会终止程序。
回答by Michael Burr
In many cases there's no reasonable recovery for an out of memory situation, in which case it's probably perfectly reasonable to let the application terminate. You might want to catch the exception at a high level to display a nicer error message than the compiler might give by default, but you might have to play some tricks to get even that to work (since the process is likely to be very low on resources at that point).
在许多情况下,对于内存不足的情况没有合理的恢复,在这种情况下,让应用程序终止可能是完全合理的。您可能希望在较高级别捕获异常以显示比编译器默认提供的更好的错误消息,但您可能需要玩一些技巧才能使其正常工作(因为该过程可能非常低那个时候的资源)。
Unless you have a special situation that can be handled and recovered, there's probably no reason to spend a lot of effort trying to handle the exception.
除非您有可以处理和恢复的特殊情况,否则可能没有理由花费大量精力尝试处理异常。