u17
u17

Reputation: 2824

Side effects of exit() without exiting?

If my application runs out of memory, I would like to re-run it with changed parameters. I have malloc / new in various parts of the application, the sizes of which are not known in advance. I see two options:

I am not thrilled by either solution. Did I miss an alternative maybe.

Thanks

Upvotes: 2

Views: 361

Answers (6)

akira
akira

Reputation: 6147

simplicity rules: just restart your app with different parameters.

it is very hard to either track down all allocs/deallocs and clean up the memory (just forget some minor blocks inside bigger chunks [fragmentation] and you still have problems to rerun the class), or to do introduce your own heap-management (very clever people have invested years to bring nedmalloc etc to live, do not fool yourself into the illusion this is an easy task).

so:

  • catch "out of memory" somehow (signals, or std::bad_alloc, or whatever)
  • create a new process of your app:
    • windows: CreateProcess() (you can just exit() your program after this, which cleans up all allocated resources for you)
    • unix: exec() (replaces the current process completely, so it "cleans up all the memory" for you)
  • done.

Upvotes: 0

Craig Wright
Craig Wright

Reputation: 1605

A way to accomplish this:

Define an exit status, perhaps like this:

static const int OUT_OF_MEMORY=9999;

Set up a new handler and have it do this:

exit(OUT_OF_MEMORY);

Then just wrap your program with another program that detects this exit status. When it does then it can rerun the program.

Granted this is more of a workaround than a solution...

The wrapper program I mentioned above could be something like this:

static int special_code = 9999;
int main()
{
   const char* command = "whatever"; 
   int status = system(command);
   while ( status == 9999 )
   {
      command = ...;
      status = system(command);
   }
   return 0;
}

That's the basicness of it. I would use std::string instead of char* in production. I'd probably also have another condition for breaking out of the while loop, some maximum number of tries perhaps.

Whatever the case, I think the fork/exec route mentioned below is pretty solid, and I'm pretty sure a solution like it could be created for Windows using spawn and its brethren.

Upvotes: 2

Ken Bloom
Ken Bloom

Reputation: 58800

Be warned that on Linux, by default, your program can request more memory than the system has available. (This is done for a number of reasons, e.g. avoiding memory duplication when fork()ing a program into two with identical data, when most of the data will remain untouched.) Memory pages for this data won't be reserved by the system until you try to write in every page you've allocated.

Since there's no good way to report this (since any memory write can cause your system to run out memory), your process will be terminated by the out of memory process killer, and you won't have the information or opportunity for your process to restart itself with different parameters.

You can change the default by using the setrlimit system call, to to limit the RLIMIT_RSS which limits the total amount of memory your process can request. Only after you have done this will malloc return NULL or new throw a std::bad_alloc exception when you reach the limit that you have set.

Be aware that on a heavily loaded system, other processes can still contribute to a systemwide out of memory condition that could cause your program to be killed without malloc or new raising an error, but if you manage the system well, this can be avoided.

Upvotes: 0

RWS
RWS

Reputation: 616

The wrapper-program (as proposed before) does not need to be a seperate executable. You could just fork, run your program and then test the return code of the child. This would have the additional benefit, that the operating system automatically reclaims the child's memory when it dies. (at least I think so)

Anyway, I imagined something like this (this is C, you might have to change the includes for C++):

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define OUT_OF_MEMORY 99999 /* or whatever */

int main(void)
{
    int pid, status;

fork_entry:
    pid = fork();
    if (pid == 0) {
        /* child - call the main function of your program here */
    } else if (pid > 0) {
        /* parent (supervisor) */
        wait(&status); /* waiting for the child to terminate */
        /* see if child exited normally
           (i.e. by calling exit(), _exit() or by returning from main()) */
        if (WIFEXITED(status)) {
            /* if so, we can get the status code */
            if (WEXITSTATUS(status) == OUT_OF_MEMORY) {
                /* change parameters */
                goto fork_entry; /* forking again */
            }
        }
    } else {
            /* fork() error */
            return 1;
    }
    return 0;
}

This might not be the most elegant solution/workaround/hack, but it's easy to do.

Upvotes: 2

Tergiver
Tergiver

Reputation: 14517

There is another option, one I have used in the past, however it requires having planned for it from the beginning, and it's not for the library-dependent programmer:

Create your own heap. It's a lot simpler to destroy a heap than to cleanup after yourself.

Doing so requires that your application is heap-aware. That means that all memory allocations have to go to that heap and not the default one. In C++ you can simply override the static new/delete operators which takes care of everything your code allocates, but you have to be VERY aware of how your libraries, even the standard library, use memory. It's not as simple as "never call a library method that allocates memory". You have to consider each library method on a case-by-case basis.

It sounds like you've already built your app and are looking for a shortcut to memory wiping. If that is the case, this will not help as you could never tack this kind of thing onto an already built application.

Upvotes: 2

PeterK
PeterK

Reputation: 6317

You could embedd all the application functionality in a class. Then let it throw an expection when it runs out of memory. This exception would be catched by your application and then you could simply destroy the class, construct a new one and try again. All in one application in one run, no need for restarts. Of course this might not be so easy, depending on what your application does...

Upvotes: 5

Related Questions