c++ - operator new doesn't return 0 when running out of memory -
i found interesting exercise in bruce eckel's thinking in c++, 2nd ed., vol.1 in chapter 13:
/*13. modify nomemory.cpp contains array of int , allocates memory instead of throwing bad_alloc. in main( ), set while loop 1 in newhandler.cpp run out of memory , see happens if operator new not test see if memory allocated. add check operator new , 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); } }
my question is: why code not throw bad_alloc
, when ran out of memory (as per task manager's resource monitor on win7)? assume global ::new char[sz]
never returns 0, if memory full. why? turns win7 os numb, non-responding state once ran out of memory, still keep on trying allocate new space.
(one interesting addition: tryed on ubuntu too: bad_alloc
not thrown either, still os not goes frozen dangerous process gets killed before os - smart isn't it?)
your implementation of operator new incorrect.
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
throws std::bad_alloc
, don't need check return value of p
pointer.
if g++
's libstdc++ source, compare pointer null after malloc
, should in order simulate this:
_glibcxx_weak_definition void * operator new (std::size_t sz) _glibcxx_throw (std::bad_alloc) { void *p; /* malloc (0) 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; }
so not return 0
throws exception
. reason why don't on linux believe process killed kernel (oom-killer) in such cases.
as @marcglisse pointed may want use nothrow
(noexcept) version of new
:
_glibcxx_weak_definition void * operator new (std::size_t sz, const std::nothrow_t&) glibcxx_use_noexcept { void *p; /* malloc (0) 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; }
as see return 0 if allocation fails , catch exceptions can raised new_handler
. default new_handler
throws std::bad_alloc
. in case think oom-killer
kill application before something. if question more why killed?
recommend read oom killer
policy.
Comments
Post a Comment