If you know exactly how much space you need to set aside and your primary concern is performance with respect to memory management and your code doesn't need to be re-entrant, then you will want to allocate objects with static storage duration, either by declaring them at file scope or by using the static
storage class specifier.
int data[SOME_NUMBER];
void foo( /* some list of parameters here */ )
{
static int some_more_data[SOME_OTHER_NUMBER];
...
}
Both data
and some_more_data
exist over the lifetime of the program, but some_more_data
is only visible within the foo
function1.
In practice, items with static storage duration have space set aside for them in the binary image itself, so that memory is available as soon as the program is loaded. This may have an advantage as far as locality is concerned; if the data and the code are in the same page, there's no need to swap. Of course, it depends on the code.
The obvious drawback is that your executable file will have a larger footprint. Another drawback is that your code isn't re-entrant; every invocation of foo
is working on the same block of memory when it reads or writes some_more_data
. Depending on what your code does, that may or may not be a big deal.
If your code needs to be re-entrant, then you can't use objects with static storage duration. If the block of data is relatively small, use objects with automatic storage duration (i.e., regular local variables).
void foo( /* some list of parameters here */ )
{
int some_more_data[SOME_SMALLISH_NUMBER];
...
}
In this case, some_more_data
only exists for the lifetime of the foo
function; each time you call foo
, it allocates another some_more_data
object automatically. Whatever overhead there is in setting aside the memory is part of the overhead of calling the function in the first place (at least in my experience). The stack pointer still gets adjusted whether you're using local variables or not, so using local variables won't make it any slower. The main issue is that the available memory for automatic objects is relatively small; for objects above a certain size, this approach simply won't work.
If your code needs to be re-entrant and you need to allocate large blocks of memory, you're pretty much stuck with dynamic memory management (malloc/calloc/realloc
and free
). Depending on how you design your code, you can minimize some of the performance issues.
1. Visibility rules are enforced during translation from source to machine code; they don't really apply at run time.