Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Memory Allocation Failure Recovery

I'm working on an embedded processor (400 MHz Intel PXA255 XScale), and I thought I saw one case where there wasn't enough memory to satisfy a 'new' operation. The program didn't crash, so I assumed other threads had freed their memory and it was just a transient thing. This is some pretty critical code, so exiting is not an option, and some sort of error needs to be returned to the remote user.

Would the following small fix be enough to solve the problem, or is there a better way? Before replacing every 'new' with the following code, I thought I'd ask.

char someArr[];
do{ 
    someArr = new char[10]; 
    Sleep(100); // no justification for choosing 100 ms
} while ( someArr == NULL );

Does the Sleep help? Should I set some max number of retries? Is it possible to use static initialization everywhere?

FINAL UPDATE: Thank you very much for the helpful responses, but it turns out there was an error in the code checking for failed memory allocation. I will keep all of these answers in mind, and replace as many malloc's and new's as I can, though (especially in error-handling code).

like image 879
Nate Parsons Avatar asked Dec 15 '08 02:12

Nate Parsons


People also ask

How do I fix memory allocation failure?

A memory allocation failure message means that the active controller is low on memory after allocating these resources and does not have enough remaining memory to control a stack member. You can correct this by reducing the number of VLANs or STP instances.

What happens if dynamically allocated memory is not freed?

If dynamically allocated memory is not freed, it results in a memory leak and system will run out of memory. This can lead to program crashing.

What happens if memory allocation fails?

In the above example, if new fails to allocate memory, it will return a null pointer instead of the address of the allocated memory. Note that if you then attempt indirection through this pointer, undefined behavior will result (most likely, your program will crash).

What is the problem of using dynamic memory allocation?

The problem with dynamic memory allocation is that it is not deallocated itself, developer responsibility to deallocate the allocated memory explicitly. If we cannot release the allocated memory, it can because of memory leak and make your machine slow.


2 Answers

You are trying to solve a global problem through local reasoning. The global problem is that the entire device has a limited amount of RAM (and possibly backing store) for the operating system and all of the applications. To make sure this amount of RAM is not exceeded, you have a few options:

  • Each process operates in a fixed amount of RAM to be determined per process at startup time; the programmer does the reasoning to make sure everything fits. So, yes, it is possible to allocate everything statically. It's just a lot of work, and every time you change your system's configuration, you have to reconsider the allocations.

  • Processes are aware of their own memory usage and needs and continually advise each other about how much memory they need. They cooperate so they don't run out of memory. This assumes that at least some processes in the system can adjust their own memory requirements (e.g., by changing the size of an internal cache). Alonso and Appel wrote a paper about this approach.

  • Each process is aware that memory can become exhausted and can fail over to a state in which it consumes a minimum amount of memory. Often this strategy is implemented by having an out-of-memory exception. The exception is handled in or near main() and the out-of-memory event essentially restarts the program from scratch. This failover mode can work if memory grows in response to user requests; if the program's memory requirements grow independent of what the user does, it can lead to thrashing.

Your proposal above matches none of the scenarios. Instead, you are hoping some other process will solve the problem and the memory you need will eventually appear. You might get lucky. You might not.

If you want your system to work reliably, you would do well to reconsider the design of every process running on the system in light of the need to share limited memory. It might be a bigger job than you expected, but if you understand the problem, you can do this. Good luck!

like image 177
Norman Ramsey Avatar answered Sep 22 '22 08:09

Norman Ramsey


There are lots of good things in the other answers, but I did think it worth adding that if all the threads get in a similar loop, then the program will be deadlocked.

The "correct" answer to this situation is probably to have strict limits for the different parts of the program to ensure that they don't over consume memory. That would probably require rewriting major sections across all parts of the program.

The next best solution would be to have some callback where a failed allocation attempt can tell the rest of the program that more memory is needed. Perhaps other parts of the program can release some buffers more aggressively than they normally would, or release memory used to cache search results, or something. This would require new code for other parts of the program. However, this could be done incrementally, rather than requiring a rewrite across the entire program.

Another solution would be to have the program protect large (temporary) memory requests with a mutex. It sounds like you are confident that memory will be released soon if you can just try again later. I suggest that you use a mutex for operations that might consume a lot of memory, this will allow the thread to be woken up immediately when another thread has released the memory that is needed. Otherwise your thread will sleep for a tenth of a second even if the memory frees up immediately.

You might also try sleep(0), which will simply hand off control to any other thread that is ready to run. This will allow your thread to regain control immediately if all other threads go to sleep, rather than having to wait out its 100 millisecond sentence. But if at least one thread still wants to run, you will still have to wait until it gives up control. This is typically 10 milliseconds on Linux machines, last I checked. I don't know about other platforms. Your thread may also have a lower priority in the scheduler if it has voluntarily gone to sleep.

like image 23
markets Avatar answered Sep 23 '22 08:09

markets