What you're looking for seems to be a resizable memory pool. Memory pools are designed for fixed amounts of memory unfortunately; that's how they minimize calls to malloc
, realloc
, etc.
In the end, you're probably better off looking at something like a different malloc
implementation (one to consider would be Google's TCMalloc; it is a part of the gperftools project) rather than memory pools, though it is C++. If you're certain that you want pools, Boost's Pool library is worth looking into. You might be able to create a C wrapper around TCMalloc, but I'm not so certain about boost::pool.
If you want to stick to working strictly with C, and you know what you're allocating ahead of time, you could create a custom type that is resizable, which will help in optimizing your malloc
and realloc
calls. You could do it with simple arrays for example:
typedef struct {
void *bytes; /* Pointer to the allocated _bytes_. */
size_t n; /* The number of _bytes_ used. */
size_t max; /* The number of _bytes_ allocated. */
} array;
The max
would always be a minimum of a certain power of 2, and it would always be a power of 2 up until a certain amount of memory is used. Then it would always be a multiple of 2 to avoid hogging too much memory, and n <= max
would always be true. That's a very simplistic view, but it's generally a good idea. Whenever you need to resize the array, instead of calling realloc
, you check whether you need to call realloc
in the first place using your own function or whether you can just increase the number of bytes used (n
in this case). That's a generalized implementation that works well with standard library functions like memcpy
and such and ANY data type. You might want a specialized form for, e.g., int
:
typedef struct {
int *ptr; /* Pointer to the allocated _items_. */
size_t n; /* Number of _items_ used. */
size_t max; /* Number of _items_ allocated. */
} int_array;
The difference between this and a malloc
implementation: malloc
is meant to handle unknown amounts of memory with unknown type, which implies unknown size. The burden here is placed upon you to keep the type, or at least the size, of each object stored in the array consistent. Otherwise, you'll have undefined behavior.* This gets you the benefit of being able to resize the allocated memory in a reasonably optimistic manner.
I will say one thing: I'm not at all certain if that will improve your performance honestly since it duplicates the effort of a malloc
implementation in most cases. TCMalloc, assuming you combined it with this idea, starts you off with ~6 MB of memory max and grows from there, perhaps by multiples of 2 or perhaps by powers of 8. I haven't checked the source quite so in-depth, so I'm not certain.
* According to ISO C, you'll technically have undefined behavior if you try to store a 4-byte int
in a 4-byte float
anyway, but that's why you shouldn't mix types, even if they're the same size.