What to do when I get a bad_alloc error?

Asked

Viewed 1,517 times

6

Before the question in question let’s assume a scenario:

  • I have some program written in GTK+;
  • The program uses the Operator new to allocate resources; (not to be confused with the Operator new (Std::nothrow))

At a certain point of the program I need to allocate a resource, and use the operator new. The operator new, if you cannot allocate memory to heap, will generate a exception of the kind std::bad_alloc.


If there is no more memory available on heap, I will not be able to draw any GTK+ window to inform the user of the problem. I can also no longer allocate any other resource (because the operator new has already informed me of the lack of memory with the std::bad_alloc).

  1. What is the best solution to be adopted at this time?
  2. I must shut down the program silently and just log in the error on std::cerr?
  3. What other possible solutions to this type of problem?

3 answers

4


My list of options is as follows::

  1. In everyday situations (non-critical), abort the program due to lack of memory is what you can do (preferably by saving a log). That’s what happens on cell phones. If the operating system overcommiting (say it has successfully allocated but only allocate memory when it is actually used), it will not do to test the malloc return (in C) nor capture the new exception (in C++) then you are screwed even.

  2. If your application has a main loop "waiting for user commands" (since it is a GTK+ application) and some well-defined start and end operations that can allocate a lot of memory, you could take the exception in the main loop and warn the user that the operation failed. Probably when returning to the main loop you already have some memory released (run the destructors). You can also warn in the message that the program may have become unstable and suggest to the user to restart it.

  3. Capturing bad_alloc in the main loop can be useful if the allocation failure was caused by another error, such as requesting -1 byte of memory, which when converted to unsigned gives a giant number. In this case the allocation error does not indicate that the system is without memory, but that some parameter has not been validated in its code, because the program should not require this colossal amount of memory.

  4. If your program needs to run continuously, consider creating a supervisory process that restarts the program whenever it is detected that it has ended unexpectedly. The new process created will resume in a much more predictable state than a program that tried to treat a bad_alloc exception!

  5. In order for bad_alloc not to occur by surprise in the middle of an operation, you could preallocate enough memory and work only within it. But be careful, as the system allocator may have some write/read protections outside the allocated area that you will lose if you try to implement everything manually (cof, Openssl, cof, Heartbleed, cof).

  6. To treat bad_alloc, you can preallocate a memory space and leave it unused, releasing only when there is an allocation error. I’ve heard this technique called "parachute".

Note that all options (except the first) are laborious and depend on how your program works (interactive? batch operations? can be restarted and continue where you left off?). It will be necessary to simulate situations of lack of memory to ensure that the treatment works properly, and take care of specific problems of certain operating systems, such as overcommiting.

If you are implementing a language, a database, or some server, these security measures are super important. If you’re implementing a Flappy Bird clone, not so much...

0

  1. In general, there is some critical procedure that may be being performed at the moment. The problem is that during shutdown more errors can be generated in the event that to close something, you need to allocate more memory. Errors can vary between segfaults or silent crashes of the application, and are especially complicated to be dealt with in case they are released by a library that you do not own the source code.

Perhaps, your application caches something (from a file, for example), and then this cache can be released, allowing the application to even continue running. But such cases are rare and vary from application to application.

  1. If it is not possible to free memory and system resources (file descriptors, etc), probably this may be the only solution, because it may be that at the time of logging, the operating system tries to allocate memory and then it also falls into a situation of bad_alloc, and in this case its application shall be terminated by.

  2. As discussed in 1., if your application creates caches or preallocates resources, it may be possible to release these resources and continue running the application normally.

This example I gave about the cache is used transparently by the Operating System.

When for example a file is opened and read, it is kept in memory for an indefinite time. Your changes, of course, are propagated to the secondary storage structure after a period of time (see parameter commit of EXT4 for more information).

The file data is then kept in memory until it is full (see note below). Then, the operating system displaces memory previously occupied by the file cache until it is sufficient to allocate it to the application by requesting it. If you want to observe this behavior, the program top, beyond the archive /proc/meminfo are the simplest methods of seeing this condition (htop does not display the numbers, not being very effective). The Task Manager Windows also displays this data, although I find them a little less intuitive and Windows is a little more aggressive in the subject I deal with in observing down below.

Observing: Freeing up memory only when a program needs it is a costly operation that can degrade application performance. Thus, the Operating System actually always keeps a free memory area, allowing the memory to be more quickly delivered to the application that needs it. Upon delivery, the OS may or may not remove data from the cache, while always keeping a free amount of memory ready for allocation. It is worth noting that disk paging is the last case to be used by the OS (although Windows again loves to escape a little from this rule).

Just to illustrate, my machine (Gentoo) has 16GB of RAM and 8GB of swap. I am using 2.8GB in applications, 5GB of buffers, 6.8GB in caches (and 0GB of swap). That is, only 1.4GB is effectively free from my RAM.

0

If you are going to miss heap memory, you should prepare your application to require more heap space when starting. It’s an action to mitigate the possibility of memory loss. But the best alternative in case of failure depends even on the purpose of your application.
If it is a high-performance critical application, you can define initial rules and parameters to ensure that a particular task can be started. So you can alert the user in case resources are not fully meeting the need. With the constant evaluation of the features, you can pause the execution and thereby avoid critical errors by informing the user of the situation and means of circumventing the problem. I don’t know exactly what the purpose and way to operate your project, but without a doubt the use of cache is an excellent alternative to managing finite resources.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.