views:

472

answers:

7

I'm currently working on a C based application am a bit stuck on freeing memory in a non-antipattern fashion. I am a memory-management amateur.

My main problem is I declare memory structures in various different scopes, and these structures get passed around by reference to other functions. Some of those functions may throw errors and exit().

How do I go about freeing my structures if I exit() in one scope, but not all my data structures are in that scope?

I get the feeling I need to wrap it all up in a psuedo exception handler and have the handler deal with freeing, but that still seems ugly because it would have to know about everything I may or may not need to free...

+2  A: 

You don't need to worry about freeing memory when exit() is called. When the process exits, the operating system will free all of the associated memory.

Michael
This was not always true. It's considered good sanitary practice to free malloc'ed structures before exit'ing. It also helps when you need to find actual memory leaks.
Edward Z. Yang
This is only for nice operating systems. It's good to free() memory when you're done with it, if only to get into the habit.
Chris Lutz
Right, I'm presuming he's discussing critical failures; i.e., the process is dying and dying fast.
Michael
-1: This is definitely not true for many operating systems.
Anthony Cuozzo
@Chris Lutz: if you're programming for a non-nice o/s, you know it and usually mention the fact in the question. Which o/s are not nice? AmigaDOS was one such, once upon a couple of decades ago.
Jonathan Leffler
@Anthony - Examples? It's true for Windows or *nix OS.
Michael
@Michael: Some of the systems I've worked with on some embedded devices were kept minimal for obvious reasons. They offered some convenient services to the application developers, but otherwise expected the developer to clean up responsibly.
Anthony Cuozzo
+4  A: 

Consider wrappers to malloc and using them in a disciplined way. Track the memory that you do allocate (in a linked list maybe) and use a wrapper to exit to enumerate your memory to free it. You could also name the memory with an additional parameter and member of your linked list structure. In applications where allocated memory is highly scope dependent you will find yourself leaking memory and this can be a good method to dump the memory and analyze it.

UPDATE: Threading in your application will make this very complex. See other answers regarding threading issues.

ojblass
You could even use the atexit() function and write a function to free all memory allocated on the linked list (which would have to be a global variable in this case) upon just a plain call to exit() - that way you wouldn't have to remember not to use plain exit().
Chris Lutz
But why? The operating system is already maintaining a list of allocated memory. You duplicating that functionality is just going to slow down the shut-down process with no benefit other than a bit of ego inflation. Unless you plan on porting your application to MSDOS, let the os do its job.
Eclipse
The why is because eventually the discipline and funcitonality will help you track down memory leaks. If you code it properly it can be turned off via a DEFINE or MACRO definitions.
ojblass
+1  A: 

You can create a simple memory manager for malloc'd memory that is shared between scopes/functions.

Register it when you malloc it, de-register it when you free it. Have a function that frees all registered memory before you call exit.

It adds a bit of overhead, but it helps keep track of memory. It can also help you hunt down pesky memory leaks.

patros
+3  A: 

I think to answer this question appropriately, we would need to know about the architecture of your entire program (or system, or whatever the case may be).

The answer is: it depends. There are a number of strategies you can use.

As others have pointed out, on a modern desktop or server operating system, you can exit() and not worry about the memory your program has allocated.

This strategy changes, for example, if you are developing on an embedded operating system where exit() might not clean everything up. Typically what I see is when individual functions return due to an error, they make sure to clean up anything they themselves have allocated. You wouldn't see any exit() calls after calling, say, 10 functions. Each function would in turn indicate an error when it returns, and each function would clean up after itself. The original main() function (if you will - it might not be called main()) would detect the error, clean up any memory it had allocated, and take the appropriate actions.

When you just have scopes-within-scopes, it's not rocket science. Where it gets difficult is if you have multiple threads of execution, and shared data structures. Then you might need a garbage collector or a way to count references and free the memory when the last user of the structure is done with it. For example, if you look at the source to the BSD networking stack, you'll see that it uses a refcnt (reference count) value in some structures that need to be kept "alive" for an extended period of time and shared among different users. (This is basically what garbage collectors do, as well.)

Mike
A: 

Very simply, why not have a reference counted implementation, so when you create an object and pass it around you increment and decrement the reference counted number (remember to be atomic if you have more than one thread).

That way, when an object is no longer used (zero references) you can safely delete it, or automatically delete it in the reference count decrement call.

Adam Hawes
+1  A: 

Michael's advice is sound - if you are exiting, you don't need to worry about freeing the memory since the system will reclaim it anyway.

One exception to that is shared memory segments - at least under System V Shared Memory. Those segments can persist longer than the program that creates them.

One option not mentioned so far is to use an arena-based memory allocation scheme, built on top of standard malloc(). If the entire application uses a single arena, your cleanup code can release that arena, and all is freed at once. (APR - Apache Portable Runtime - provides a pools feature which I believe is similar; David Hanson's "C Interfaces and Implementations" provides an arena-based memory allocation system; I've written one that you could use if you wanted to.) You can think of this as "poor man's garbage collection".

As a general memory discipline, every time you allocate memory dynamically, you should understand which code is going to release it and when it can be released. There are a few standard patterns. The simplest is "allocated in this function; released before this function returns". This keeps the memory largely under control (if you don't run too many iterations on the loop that contains the memory allocation), and scopes it so that it can be made available to the current function and the functions it calls. Obviously, you have to be reasonably sure that the functions you call are not going to squirrel away (cache) pointers to the data and try to reuse them later after you've released and reused the memory.

The next standard pattern is exemplified by fopen() and fclose(); there's a function that allocates a pointer to some memory, which can be used by the calling code, and then released when the program has finished with it. However, this often becomes very similar to the first case - it is usually a good idea to call fclose() in the function that called fopen() too.

Most of the remaining 'patterns' are somewhat ad hoc.

Jonathan Leffler
A: 

This sounds like a task for a Boehm garbage collector.

http://www.hpl.hp.com/personal/Hans_Boehm/gc/

Depends on the system of course whether you can or should afford to use it.

3yE