If a malloc
allocation fails, should we try it again?
In something like this:
char* mystrdup(const char *s)
{
char *ab = NULL;
while(ab == NULL) {
ab=(char*)malloc(strlen(s)+1);
}
strcpy(ab, s);
return ab;
}
Is the while loop valid for checking the memory allocation?
The behavior is undefined, but most likely you'll get a negative result. Remember that the type of an expression in C is determined by the expression itself, not by the context in which it's evaluated.
Consider a case where function A() constructs a linked-list and in each iteration it calls to another function, B() . Now, if a malloc failure occured at B() , it must free() the memory it allocated but function A() should do that as well.
But yes, malloc can fail on Linux. You're correct in the way that it's default behavior, but the behavior can be turned off. Also, if you're using cgroups (or anything that leverages that like containers) you can put a limit on the memory resource and then malloc will fail.
The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory. If the allocation fails, it returns NULL.
In general, a modern malloc()
implementation will return NULL
only as an absolute last resort, and trying again will definitely not help. The only thing that will help is freeing some memory and then trying again. If your application holds any expendable resources, this would be the time to free them, and then give it another shot.
In some environments, a useful practice is to allocate a small amount of memory as a rainy-day fund. If malloc()
ever does return NULL
, you can free that rainy-day fund, and then allocate whatever resources you need to be able to handle the error and exit gracefully. This was a common practice when programming with the old Macintosh Toolbox; if malloc()
returned NULL
, you could use that space to create a dialog to report the problem before exiting.
In a single-threaded program "trying again" without freeing any memory between tries make no practical sense. It will just loop forever.
In a multi-threaded program this might "work", if another thread running in parallel suddenly decides to free some of its own memory. The loop in such case would constitute a classic "busy waiting" loop. But even in this case such code has very little practical value for more reasons than one.
No, never. If malloc
returns NULL, that indicates an error, and you should probably abort.
Without arguing why or when this would be useful, attempts to reallocate in a loop could work, at least on Windows with 64 bit code, and default pagefile settings. Moreover, this could buy surprisingly more additional virtual memory. Although, do not do this in an infinite loop, but instead use a finite number of retries. As a proof, try the following code that simulates leaking 1 Mb of memory. You have to run it in Release build, preferably not under debugger.
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);
}
On my machine with 8 Gb of RAM and system managed pagefile, I get the following output (built with VS2013 for x64 target, tested on 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
I don't know exact reason of such behavior, but it seems allocations start failing once the pagefile resizing cannot keep up with requests. On my machine, pagefile grew from 8 gb to 20 Gb after this loop (drops back to 8 Gb after the program quits).
It is incredibly unlikely that this will do what you want; if you're out of memory, busy-looping until you get more is likely to be disappointing. You should just return the NULL to the calling program so that it can deal with resource exhaustion, either by releasing memory it no longer needs or by returning an error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With