Testing Memory Allocation Failure
15 December 2004, evening time
When programming in C a programmer usually uses the malloc
function to request memory on the heap. In C++ one can use malloc
, but generally the proper thing to do is use new
, and for arrays new[]
. The new
operator, when successful, returns a block of memory big enough for the object or array one wishes to store. Unfortunately, sometimes new
and malloc
will fail to find any memory.
Now, in C the proper thing to do is check that the memory was allocated before an attempt to use it. malloc
returns 0 when it fails to find enough free memory. The common idiom in C then is to test if the value of the pointer pointing to the memory requested is NULL
(0) after a call to malloc
.
...
int* my_int_ptr = malloc( sizeof(int) );
if ( 0 == my_int_ptr ) {
// handle error
}
...
- Download this code: /static/code/9.txt
I was vaguely aware that in C++ things were different, but didn’t concern myself with learning exactly how different till today. If a computer fails to allocate memory after a call to new
or malloc
, chances are the computer is on the verge of crashing. As such, for most programs a reasonable course of action when a new
or malloc
fails is to simply terminate. However, there are many applications where this is not a reasonable thing to do. When faced with writing such an application, it helps to know what will happen when new
fails.
A normal call to new
throws a bad_alloc
exception. If this is not caught, it will get transformed into a std::terminate()
call. std::terminate()
by default calls abort()
, which exits the running program and does not run destructors for static objects. This is quite different from malloc
. The following program will crash (on my local machine the program outputs ‘Aborted’):
#include <iostream>
int main() {
const int n = 0x7FFFFFFF;
for (;;) {
char* memory = new char[n];
if ( 0 == memory ) {
std::cerr << "Operator new returns a NULL";
} else {
memory[0] = 'A';
memory[n-1] = 'B';
std::cout << "A-OK";
}
}
return 0;
}
- Download this code: /static/code/6.txt
Testing for NULL
will accomplish nothing, the program will still crash. To have new
behave like malloc
when it fails one must call the overloaded version of new
, new(nothrow)
. Doing so will result in new
not throwing an exception and returning NULL
if it fails. This program will print “Operator new returns NULL” forever:
#include <iostream>
int main() {
const int n = 0x7FFFFFFF;
for (;;) {
CHAR* memory = new(std::nothrow) char[n];
if ( 0 == memory ) {
std::cerr << "Operator new returns a NULL";
} else {
memory[0] = 'A';
memory[n-1] = 'B';
std::cout << "A-OK";
}
}
return 0;
}
- Download this code: /static/code/7.txt
By default new
uses the advanced erorr handling capabilities of C++. As such, using new(nothrow)
is really not a good solution when one needs to write a robust program. One should make it a point to catch the bad_alloc
exception a call to new may throw, and handle it appropriately. This program will print “New throws a bad_alloc exception” forever:
#include <iostream>
int main() {
const int n = 0x7FFFFFFF;
for (;;) {
try {
char* memory = new char[n];
memory[0] = 'A';
memory[n-1] = 'B';
std::cout << "A-OK";
}
catch (std::bad_alloc)
{
std::cerr << "New throws a bad_alloc exception";
}
}
return 0;
}
- Download this code: /static/code/8.txt
And that is more then you probably wanted to know about new
.
Cool. What happens in Java?
by Ryan on December 16 2004, 3:05 am #
You read my mind. I was thinking about that on the bus ride home, but haven’t had a chance to look into it yet. I suspect that the JVM will probably raise an exception.
by ramanan on December 16 2004, 10:39 am #
Java does indeed throw an exception on a failure to allocate memory:
OutOfMemoryError
.by ramanan on December 16 2004, 12:46 pm #
Can you tune if up, like C++, though? Throwing an exception seems like the best way to go though.
by Ryan on December 17 2004, 5:40 am #
Question: We allocated two dynamic heaps, one of which can be destroyed (lets call it heap2). We run out of memory when trying to allocate for heap1. We then destroy heap2 and have lots of memory available again. But when we try to allocate for heap 1 again, it still thinks there is no memory available.
We are however able to create a new heap and allocate. It is just the existing heap that refuses to grow.
What stops the allocate?
by karen on June 20 2007, 3:04 pm #
Further on the above question: We are able to allocate massive amounts of memory to the new heap (e.g. 2.1 GB). It is just the existing heap that refuses to grow even though it was created with an initial size 0 i.e. a growable heap.
by karen on June 20 2007, 3:19 pm #
I have no clue, based on your two comments. What OS is this all taking place on? When you say Dynamic Heap, do you mean an STL heap?
by ramanan on June 20 2007, 4:07 pm #