Scoped Memory Management

Background

Memory management in C is notoriously problematic. Matching every malloc, calloc and strdup with a free for all code paths is error prone and code intensive. This library provides scoped memory. A scoped memory block can be created once and allocated from many times. When the work is done the entire block can be freed with a single call. It is significantly easier to manage and safer to use than the conventional C memory functions.

Features

  • Scoped memory blocks, sometimes referred to as ‘arena’ memory provide a leak free pool of memory to allocate from in an ad hoc manner, that can be easily freed in one call.

  • The functions mimic standard library memory management calls, so are easy to remember.

  • Memory scopes automatically expand up to all available memory.

An Example

#include <c-craft/mem.h>

typedef struct person
{
    char *name;
    char *address;
    struct person *children[];
}
PERSON;

MEM_SCOPE mem = sm_create(0);
PERSON *person = sm_alloc(mem, sizeof(person));
person->name = sm_strdup(mem, "Jim Smith");

/* Space for one entry and NULL terminator. */
person->children = sm_calloc(mem, 2, sizeof(PERSON *));
person.children[0] = sm_alloc(mem, sizeof(PERSON));

person[0]->name = sm_strdup(mem, "Rose Smith");
person[0]->address = "";

/* ...  do some work etc... */

sm_free(mem);    /* Frees names and children also */

In this example, note that “Jim Smith”, could have been added directly as a string constant without using sm_strdup(). If he had, the sm_free() call would still work correctly and without the risk of an unintended and incorrect call to free().

Scoped Memory Context

A MEM_SCOPE returned from sm_create(0) forms a memory context. You can use this context for ad hoc memory allocation and free all the memory by freeing the context with sm_free(). The memory is allocated in chunks behind the scenes, and is expanded on demand to cope with allocation requests. You may specify a block size as small as you need, if memory is a critical resource. Note that this example uses 0 for block size indicating to use a default size for all new blocks.

Custom Allocators

Scoped memory uses malloc() and free() to obtain memory for all scoped memory functions. If your system requires custom memory allocation it is possible to redirect allocation requests to your custom allocator. You only need to supply a custom version of malloc() and free(), as these are the only two memory allocation calls used by scoped memory.

Compatibility

You may still use malloc() and friends, if you have a use case for it. You can intermingle standard C memory allocation calls with scoped memory allocation. Unsurprisingly, however, you must use free() for anything you malloc(), calloc() or strdup().

Caveats

Because scoped memory has no concept of free, other than for the entire scope, re-allocation has little value. A working version of the realloc() function is provided for completeness, but the implementation simply allocates a new block and copies the data to it. No memory is released.

Summary

Scoped memory allows you to manage the memory for all the objects in an object model. A single call can release all the memory allocated to the objects within any object hierarchy. By using scoped memory you can allocate and return a complete object model graph of any complexity from a function and guarantee to a client that all the memory will be released with a single call on just the context of the MEM_SCOPE. Scoped memory allocation helps to ensure memory leaks are prevented.