运算符 new 在内存不足时不返回 0
operator new doesn't return 0 when running out of memory
我在Bruce Eckel的Thinking in c++, 2nd edition, Vol.1第13章中找到了这个有趣的练习:
/*13. Modify NoMemory.cpp so that it contains an array of int
and so that it actually allocates memory instead of
throwing bad_alloc. In main( ), set up a while loop like
the one in NewHandler.cpp to run out of memory and
see what happens if your operator new does not test to
see if the memory is successfully allocated. Then add the
check to your operator new and throw bad_alloc*/
#include <iostream>
#include <cstdlib>
#include <new> // bad_alloc definition
using namespace std;
int count = 0;
class NoMemory {
int array[100000];
public:
void* operator new(size_t sz) throw(bad_alloc)
{
void* p = ::new char[sz];
if(!p)
{
throw bad_alloc(); // "Out of memory"
}
return p;
}
};
int main() {
try {
while(1) {
count++;
new NoMemory();
}
}
catch(bad_alloc)
{
cout << "memory exhausted after " << count << " allocations!" << endl;
cout << "Out of memory exception" << endl;
exit(1);
}
}
我的问题是:为什么这段代码不抛出bad_alloc
,当完全耗尽内存时(根据Win7上的任务管理器的资源监视器)?我假设全局::new char[sz]
永远不会返回0,即使内存已满。但是为什么呢?它甚至把Win7系统变成一个麻木的,无响应的状态,一旦内存用完,它仍然继续尝试分配新的空间。
(一个有趣的补充:我也在Ubuntu上尝试过:bad_alloc
也没有被抛出,仍然这个操作系统不会冻结,但是这个危险的进程在操作系统之前被杀死-智能不是吗?)
操作符new的实现不正确。
void* operator new(size_t sz) throw(bad_alloc)
{
void* p = ::new char[sz];
if(!p)
{
throw bad_alloc(); // "Out of memory"
}
return p;
}
::new
已经抛出std::bad_alloc
,你不需要检查p
指针的返回值
如果你看一下g++
的libstdc++源代码,他们在malloc
之后比较指针为空,所以你也应该这样做,以模拟这个:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
void *p;
/* malloc (0) is unpredictable; avoid it. */
if (sz == 0)
sz = 1;
while (__builtin_expect ((p = malloc (sz)) == 0, false))
{
new_handler handler = std::get_new_handler ();
if (! handler)
_GLIBCXX_THROW_OR_ABORT(bad_alloc());
handler ();
}
return p;
}
所以它不返回0
,而是抛出exception
。我认为,在linux上不使用它的原因是,在这种情况下,进程总是被内核(om - killer)杀死。
正如@MarcGlisse指出的,你可能想使用nothrow
(noexcept)版本的new
:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz, const std::nothrow_t&) GLIBCXX_USE_NOEXCEPT
{
void *p;
/* malloc (0) is unpredictable; avoid it. */
if (sz == 0)
sz = 1;
while (__builtin_expect ((p = malloc (sz)) == 0, false))
{
new_handler handler = std::get_new_handler ();
if (! handler)
return 0;
__try
{
handler ();
}
__catch(const bad_alloc&)
{
return 0;
}
}
return p;
}
如您所见,如果分配失败,它将返回0,并且它将捕获new_handler
可能引发的所有异常。默认的new_handler
抛出std::bad_alloc
。但即使在这种情况下,我认为OOM-Killer
会在你得到一些东西之前杀死你的应用程序。如果你的问题更多是关于why is it killed?
的,那么我建议你阅读OOM killer
的政策。
我发现我的错误:我叫new
错误:new NoMemory();
正确的做法是new NoMemory;
(不带括号)
现在它像一个魅力,像这样:
#include <iostream>
#include <cstdlib>
#include <new> // bad_alloc definition
using namespace std;
int count = 0;
class NoMemory {
int array[100000];
public:
void* operator new(size_t sz) throw(bad_alloc)
{
void* p = ::new(std::nothrow) char[sz];
if(0 != p)
return p;
throw bad_alloc();
}
};
int main() {
try {
while(1) {
count++;
new NoMemory;
}
}
catch(bad_alloc)
{
cout << "memory exhausted after " << count << " allocations!" << endl;
cout << "Out of memory exception" << endl;
exit(1);
}
}
- 是否值得降低我的代码的可读性,以便在出现内存不足错误时提供异常安全性?
- 在内存不足之前,我可以声明多少个 const 变量?
- 如何避免由于内存不足而导致 gcc 崩溃
- 检测到由于操作系统内存不足而导致子进程终止
- 导出 vulkan 内存分配句柄会导致设备内存不足
- 如何消除ROS打开CV中的内存不足错误?
- 返回内存异常错误的矢量
- 32 位应用程序内存不足
- 在本机 Android 应用中处理内存不足
- 在 Linux 上C++的无限循环中捕获内存不足的错误 bad_alloc()
- 处理静态数组内存C++的内存不足情况
- 访问违规可以是一个伪装的内存不足错误吗
- g++ 内存不足为 std::bitset 分配
- C++ 分配器在内存不足时使应用程序崩溃
- 使用队列的非递归回溯:内存不足
- 数组中的值之和返回内存地址,除非sizeof(array)/2
- C++ : 内存不足时应返回什么?
- 使用 sqlite3 时内存不足
- 运算符 new 在内存不足时不返回 0
- 一旦 cudaMalloc 返回内存不足,每个 cuda API 调用都会返回失败