malloc vs realloc - what is the best practice? - c

I have a variable where the size is determined in run-time.
Is it generally better to realloc it every time a new element is added like:
array_type * someArray;
int counter = 0;
//before a new element is added:
counter ++;
someArray = realloc(someArray, counter * sizeof(array_type));
Or allocate more memory than probably needed using malloc once:
array_type * someArray = malloc(ENOUG_MEMORY * sizeof(array_type));
What is best in terms of efficiency(speed), readability and memory-management? And why?

realloc could occasionally be useful in the past, with certain allocation patterns in single-threaded code. Most modern memory managers are optimized for multi-threaded programs and to minimize fragmentation, so, when growing an allocation, a realloc will almost certainly just allocate a new block, copy the existing data, and then free the old block. So there's no real advantage to trying to use realloc.
Increasing the size one element at a time can create an O(n^2) situation. In the worst case, the existing data has to be copied each time. It would be better to increase the size in chunks (which is still O(n^2) but with a smaller constant factor) or to grow the allocation geometrically (which gives an O(n) amortized cost).
Furthermore, it's difficult to use realloc correctly.
someArray = realloc(someArray, counter * sizeof(array_type));
If the realloc fails, someArray is set to NULL. If that was your only copy of the pointer to the previously allocated memory, you've just lost it.
You won't be able to access the data you had already placed, and you can't free the original allocation, so you'll have a memory leak.

What is best in terms of efficiency(speed), readability and memory-management? And why?
There is no general best. Specific best depends on your specific application and use case and environment. You can throw wars over perfect realloc ratio and decide if you need realloc at all.
Remember about rules of optimization. You do not optimize. Then, you do not optimize, without measuring first. The best in any terms can be measured for your specific setup, your specific environment, your specific application that uses specific operating system and *alloc implementation.
what is the best practice?
Allocating a constant amount of memory (if it's small enough) is static. It's just an array. Refactor you application to just:
array_type someArray[ENOUGH_MEMORY];
If you do not want to over allocate (or ENOUGH_MEMORY is big enough), then use realloc to add one element, as presented.
If you want, "optimize" by not calling realloc that often and over allocating - it seems that ratio 1.5 is the most preferred from the linked thread above. Still, it's highly application specific - I would over allocate on Linux, I would not when working on STM32 or other bare metal.

I would use realloc with caution.
Calling realloc in general leads to:
allocating completely new block
copying all data from old to new location
releasing (freeing) the initial block.
All combined could be questionable from performance perspective, depending on the app, volume of data, response requirements.
In addition, in case of realloc failure, the return value is NULL which means that allocation to new block is not straightforward (indirection is required). E.g.
int *p = malloc(100 * sizeof *p);
if (NULL == p)
{
perror("malloc() failed");
return EXIT_FAILURE;
}
do_something_with_p(p);
/* Reallocate array to a new size
* Using temporary pointer in case realloc() fails. */
{
int *temp = realloc(p, 100000 * sizeof *temp);
if (NULL == temp)
{
perror("realloc() failed");
free(p);
return EXIT_FAILURE;
}
p = temp;
}

malloc vs realloc - what is the best practice?
Helper functions
When writing robust code, I avoid using library *alloc() functions directly. Instead I form helper functions to handle various use cases and take care of edge cases, parameter validation, etc.
Within these helper functions, I use malloc(), realloc(), calloc() as building blocks, perhaps steered by implementation macros, to form good code per the use case.
This pushes the "what is best" to a narrower set of conditions where it can be better assessed - per function. In the growing by 2x case, realloc() is fine.
Example:
// Optimize for a growing allocation
// Return new pointer.
// Allocate per 2x *nmemb * size.
// Update *nmemb_new as needed.
// A return of NULL implies failure, old not deallocated.
void *my_alloc_grow(void *ptr, size_t *nmemb, size_t size) {
if (nmemb == NULL) {
return NULL;
}
size_t nmemb_old = *nmemb;
if (size == 0) { // Consider array elements of size 0 as error
return NULL;
}
if (nmemb_old > SIZE_MAX/2/size)) {
return NULL;
}
size_t nmemb_new = nmemb_old ? (nmemb_old * 2) : 1;
unsigned char *ptr_new = realloc(ptr, nmemb_new * size);
if (ptr_new == NULL) {
return NULL;
}
// Maybe zero fill new memory portion.
memset(ptr_new + nmemb_old * size, 0, (nmemb_new - nmemb_old) * size);
*nmemb = nmemb_new;
return ptr_new;
}
Other use cases.
/ General new memory
void *my_alloc(size_t *nmemb, size_t size); // General new memory
void *my_calloc(size_t *nmemb, size_t size); // General new memory with zeroing
// General reallocation, maybe more or less.
// Act like free() on nmemb_new == 0.
void *my_alloc_resize(void *ptr, size_t *nmemb, size_t nmemb_new, size_t size);

Related

Array of strings memory reallocation in C

I have a project to do and I need to reallocate the memory for the array. I tried many times, but I have found just one version that works.
void resize(int* size, char*** arr)
{
*size *= 2;
*arr = realloc(*arr, sizeof(char*) * *size);
nulltest(*arr); // This checks if the allocation was successful
}
resize(&size, &arr);
This function doubles the capacity of the array, but I think it's done too complicated, so I want to ask you guys, if this can be simplified or not. I'm open to new solutions too.
int is not the good type for sizes. Use the correct one size_t
Try to avoid side effects (ie modifying the objects passed by reference) without special need.
Your code is potentially leaking memory. If realloc failes you loose the reference to the previously allocated memory. The integer referenced by size is also changed without the need.
I would implement it this way:
char **resize(char **arr, size_t newsize)
{
return realloc(arr, size * sizeof(*arr));
}
And the caller function should check for the errors.
But what is the point of defining this function? This one only returns the return value of realloc.

What's the time complexity of realloc function in C?

I have a question: what's the time complexity of realloc function?
For example, I have an array of integers: a[10]. Of course, the array has been dynamically allocated in this way =>
int *a = (int*)malloc(10*sizeof(int));
And then I want to resize this array to 11 in order to insert an additional value to the array a, so I do =>
a = (int*)realloc(a, 11*sizeof(int));
My question is: What's the time complexity of reallocation? Does realloc simply add an additional cell into the array and then it takes O(1) or it recopies the whole array a, add the additional 11th cell and return the new-sized array and in this case the time complexity of this action is O(n)? Which assumption is true?
First, your code (in the original form of your question) is wrong. It should at least be
a = realloc(a, 11*sizeof(int));
(otherwise you probably have undefined behavior, in the usual case when sizeof(int) is greater than one). BTW realloc should not be casted in C.
Then, your question
What's the time complexity of realloc function in C?
Has no sense, unless you speak of some particular realloc function whose implementation you do know.
Notice that realloc is allowed to fail. Here is an efficient but useless and constant-time implementation of it (see also this answer; it is a standard conforming realloc which follows the letter, but not the spirit, of the standard n1570):
void *realloc( void *ptr, size_t new_size ) {
errno = ENOMEM;
return NULL;
}
At last, in practice, you could consider malloc and realloc as somehow expensive operations (typical runtime could be several microseconds, so thousands of time slower than an addition), and in many cases you don't want to realloc on every loop. So you'll rather use some geometrical growth for realloc (like here)
Does realloc simply add an additional cell into the array and then it takes O(1) or it recopies the whole array a, add the additional 11th cell and return the new-sized array and in this case the time complexity of this action is O(n)?
Both can happen. You could imagine that malloc keeps somewhere the allocated size (rounded up by the implementation...) and in good cases realloc returns the same pointer (so O(1)) and in less happy cases it need to copy the memory zone elsewhere. Without knowing your particular implementation (of malloc, realloc, free) you cannot know what is the most common case, or their probability distribution. BTW, it seems that a realloc implementation which always copy data (or fail) is conforming to the standard (but inefficient). If you need to know more, you should benchmark.
At last, many implementations of the C standard library are free software (e.g. GNU libc, musl-libc, ...) and you might study their source code of malloc, free, realloc (above operating system primitives -usually system calls- growing the virtual address space; on Linux, something like mmap(2))
realloc is equivalent to:
void *
realloc(void *old, size_t new_size)
{
size_t old_size = internal_function_that_knows_old_size(old);
void *new = malloc(new_size);
if (new == NULL)
return NULL;
size_t sz = old_size;
if (new_size < old_size)
sz = new_size;
memcpy(new, old, sz);
free(old);
return new;
}
It is possible for realloc to have optimizations that in some situations makes it faster, but I'm pretty sure that it's impossible to make those optimizations always work, so the fallback will always be a function that does something like the above, so you should consider this your worst case.
Now, when it comes to time complexity, there is nothing in the standard that requires malloc or free have any reasonable behavior so it is possible that they will dominate the runtime of this function (or internal_function_that_knows_old_size will), but since those bits of the system are usually quite well written that is unlikely. The dominant part (at least for large n, which is where complexity is interesting) will be the memcpy.
So with some reasonable assumptions realloc has to be O(n) (with n being the old or new size of the allocation whichever is smaller).

Fastest way possible to allocate an array of strings

I have a function which takes an array of strings (buffer) and needs to increase its size.
So I invoke a realloc
temp = (char**) realloc (buffer, newSize * (sizeof(char*)));
if (temp == NULL)
return false;
else
buffer = temp;
And thus far everything is fine. Now for every new cell I must invoke a malloc with the correct size. Notice that newSize is always even and that odd strings have a different length than even ones.
for (i = oldSize; i < newSize; i++){
support = (char*) malloc (LENGTH1 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
i++;
support = (char*) malloc (LENGTH2 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
}
The fact is that since I work with huge data sooner or later I'll finish memory and the realloc or one of the mallocs will fail. The problem is that if it's one of the mallocs the one that fails there is the risk that I'll have to invoke millions of free to clear up some memory. This takes a lot of time. Is there any way to speedup this process or even better avoid it?
if (failedMalloc){
for (i = oldRows; i < marker; i++)
free(buffer[i]);
temp = (char**) realloc (buffer, oldRows * (sizeof(char*)));
}
PS: Yes I know that pointer arithmetic is faster than array indexing. I will implement it when I find a way to solve this problem, for the moment I prefer using array indexing because I find it less error prone. But the final version will use pointer arithmetic
Instead of allocating each string individually, allocate them in blocks. You could for example malloc 128*(LENGTH1+LENGTH2) and have room for 256 consecutive strings. Whenever your index crosses a block boundary, malloc another big block and use modulo arithmetic to get an offset into it for the start of the string.
P.S. sizeof(char) is guaranteed to be 1.
Allocate larger blocks of memory. The less malloc calls, the better. The fastest will be to precalculate the required size and allocate only once.
Also, using pointer arithmetic will not produce any visible difference here.
You could write your own allocation and deallocation routines, and use them instead of malloc/free for the strings. If your routines malloc one or more big buffers and portion out little bits of it, then you can free the whole lot in one go just by calling free on each big buffer.
The general idea works especially well in the case where all allocations are the same size, in which case it's called a "pool allocator". In this case, for each array or strings you could have one associated pool for the LENGTH1 allocations, and another for the LENGTH2.
I say, "write your own", but no doubt there are simple open-source pool allocators out there for the taking.
One way to avoid waste memory is to malloc larger memory each time, when you need to malloc,
malloc fixed size(align to 2^n), e.g.
int m_size = 1;
// when need malloc
while (m_size < require_size) m_size * 2;
malloc(m_size);

How does realloc know how much to copy?

how does realloc know the size of original data?
void *realloc(void *ptr, size_t size);
So, if the implementation is like this:
temp = malloc(size);
memcpy(.. // How much to copy?
free(ptr);
return temp;
I realize this is not the original implementation, and realloc doesn't always do free, but when it does, how much does it copy?
Edit:
Thanks for the answers. But how can I then implement realloc in my code with malloc/free/..?
It knows because malloc recorded that information when you called it. After all, the system has to keep track of the sizes of allocated blocks anyway so that it doesn't allocate a particular region of memory twice.
If you mean, "how does it know how much of the array I've written in so far", it doesn't need to. It can just copy any uninitialised garbage as well.
But how can I then implement realloc in my code with malloc/free/..?
If you're already using malloc & free, why not just use realloc?
else you can just have a look at the CRT source that ships with MSVC/gcc etc. (or just download it, in the case of GCC), and see how they implement it.
If your running a custom allocator, then its a little more situational, eg: I use a binary bin with a slab type system, in which case realloc is simple:
void* Reallocate(Manager* pManager, void* pBlock, size_t nSize, const char* szFile, const DWORD dwLine)
{
#if ( MMANAGER_NULL_TO_DEFAULT )
if(pManager == NULL)
pManager = MMANAGER_DEFUALT_MANAGER;
#endif
if(pBlock == NULL)
return Allocate(pManager,nSize,szFile,dwLine);
else if(nSize == 0)
{
Free(pManager,pBlock,szFile,dwLine);
return NULL;
}
BlockHeader* pHeader = GetHeader(pBlock);
size_t nPrevSize = pHeader->pPoolBlock->nSize;
if(nPrevSize < nSize)
{
void* pNewBlock = Allocate(pManager,nSize,szFile,dwLine);
memcpy(pNewBlock,pBlock,nPrevSize);
PoolBlock* pPoolBlock = pHeader->pPoolBlock;
if(pPoolBlock == NULL)
free(pHeader);
else
FreeBlock(pPoolBlock,pHeader);
return pNewBlock;
}
return pBlock;
}
realloc (and malloc and free) have full access to the entire datastructure that makes up the heap. In that datastructure is information about the sizes of blocks, which realloc needs to know, and so does free.
When you malloc some memory, the block you get is usually a fixed offset into a larger data structure that also holds extra information, notably the size of the block. You can verify that this is true on some systems by just noting that every address returned by malloc ends in 8 when printed in hex (e.g., with the %p substitution to printf). Of course, realloc can reverse this offset and get back to the memory management structure, and so get the size; from there, being able to know how much to copy (when necessary) is trivial…
Why don't you just look up how malloc/calloc/realloc/free is implemented in the C standard library you're using?
Or, if you don't have access to the source code, look at how it's implemented in one of the open-source C standard libraries.

Per thread memory allocation

I am working on a trace tool for multithread applications, more especially about memory allocation.
I would like a per thread memory allocation. I know that when a thread do a malloc, the memory used is the global heap. I would like to trace which thread allocated how much memory.
I did a wrapper upon malloc, incrementing values each time there is a malloc as:
void *mymalloc(size_t size) {
mem_used[thread_id] += size;
return malloc(size);
}
It works well. The problem is with free method, which does not return how much memory is released.
Don't take into account my solution, it is just to show what I tried.
EDIT:
As mentionned above, keeping my own table is a too heavy method.
how about changing mymalloc to do:
int* mymem = malloc(size + sizeof(int)*2);
mymem[0] = thread_id;
mymem[1] = size;
mem_used[thread_id] += size;
return &mymem[2].
Then, in myfree(void* mem), you:
void myfree(void* mem)
{
int* imem = (int*)(mem - sizeof(int)*2);
int thread_id = imem[0];
int size = imem[1];
mem_used[thread_id] -= size;
free(imem);
}
this can be optimized, but I hope you get the idea...
The only think I can think of (although you probably considered this) is keeping an allocation table whit these columns:
ThreadID (of course)
Pointer
Allocated size
Then, you will have to use your own malloc and free functions to do the actual mallocing and freeing, but also keeping the allocation table updated.
Is this for debugging purposes? Because otherwise, the overhead of maintaining this table can be significant.
It's a little more complicated. Off the top-of-my-head:
Create a map with the pointer value and memory size allocated for that pointer.
In your my_malloc, update the map with the size argument.
Write your own wrapper for free subtracting the size (which you retrieve by looking up the pointer value) for that thread.

Resources