In a system where I'm limited with CPU power and memory, I was wondering if I can use this trick (which doesn't work) to gain some performance. The goal is to reduce memory and CPU usage.
Let's say I allocated 6*sizeof(int)
at some point during runtime and I don't need the first value of the pointer later anymore. At this point I will have a portion of that allocated memory, more specifically 1*sizeof(int)
that the program doesn't need and cannot use.
So my first idea is to allocate 5*sizeof(int)
in another pointer, move the data through and free the first one, but by doing this I will have to use more memory for a short duration (2 pointers) and by moving data from addresses to other addresses I'll lose CPU performance.
My second idea was better in theory but it didn't work, instead of moving data, I can directly allocate the second pointer to the second address of the first pointer, and by doing that, I didn't have to use the CPU to move data and my new pointer is working fine until I free the old one... Basically this is the code I tried:
void Print(int* k, int size)
{
for(int i=0;i<size;i )
{
printf("%d, ",k[i]);
}
}
void Scan(int* k, int size)
{
for(int i=0;i<size;i )
{
k[i] = i 1;
}
}
int main() {
int* a = malloc(6 * sizeof(int));
Scan(a,6);
Print(a, 6);
int* p = malloc(5 * sizeof(int));
p = a 1;
free(a);
Print(p, 5);
return 0;
}
Is there a way to make it work please?
CodePudding user response:
TL;DR: No, there is no way to make it work (using the system's allocator).
free()
neither has nor wants any awareness of pointers to or into an allocated block, except only the copy it receives (by value) as its first parameter. And it works only in terms of whole blocks previously allocated by malloc()
or calloc()
. Therefore, you cannot use free to reduce a memory allocation.
You can use realloc()
to shrink a memory allocation, but
The memory is released from the high-address end of the allocation, contrary to what you want. You would need to shift the data you want to keep to the beginning of the array.
The change is not necessarily performed in place, even when you reduce the size (as opposed to increasing it). That means you might be even worse off with
realloc
than with the first strategy you described. You could end up with the same temporary use of extra memory and the same cost to copy, plus the cost to shift the array contents as described in (1).It's probably not useful to release an
int
-size portion of a six-int
-sized region anyway, because allocators don't usually operate with fine enough granularity for that to make a difference. You can reduce the formal allocation size, but that probably would not, in practice, make any additional space available for the program to allocate.
CodePudding user response:
That won't work -- you have to call free()
on the exact pointer that was previously returned by malloc()
, and the call to free()
will always free the entire amount of memory that was previously allocated by the malloc()
call. Partial-frees aren't supported by malloc()
and free()
.
If you want to change the size of an existing heap allocation, you can attempt to do so by calling realloc() on it. Be aware that realloc()
is tricky to use correctly, though (e.g. it returns a new pointer-value that you should use instead of the old one). e.g. if you wanted to remove the first int
from front of your 6-int heap-allocation, you'd need to copy each of the 5 following ints
over the int
that was before it, then do a = realloc(a, 5*sizeof(int))
. Whether doing that would actually save you a measurable amount of RAM or CPU usage is an open question (personally I doubt it, unless it's actually several thousand or more ints
you want to remove, not just one).
Probably your best bet is to give up on fancy separate heap-allocations and just use pointer-math to get the job done:
int main() {
int* a = malloc(6 * sizeof(int));
Scan(a,6);
Print(a, 6);
Print(a 1, 5);
free(a);
return 0;
}
... and for the example code given, you don't need the first heap-allocation either, so you can reduce your program's complexity and memory usage by going with a stack-array instead:
int main() {
int a[6];
Scan(a,6);
Print(a, 6);
Print(a 1, 5);
return 0;
}
CodePudding user response:
breaking this code down
int main() {
int* a = malloc(6 * sizeof(int)); // allocate 6 ints
Scan(a,6);
Print(a, 6);
int* p = malloc(5 * sizeof(int)); // allocate 5 ints
p = a 1; // overwrite the pointer to those 5 ints ==> leak
free(a); // release the memory the p points at
Print(p, 5); // undeifined behavior
return 0;
}
this will work tho
int main() {
int* a = malloc(6 * sizeof(int));
Scan(a,6);
Print(a, 6);
int* p = a 1; // new pointer to malloced memory that skips the first entry
Print(p, 5);
return 0;
}