Home > OS >  how to free specific size of memory allocated in C
how to free specific size of memory allocated in C

Time:12-22

I allocate a memory of size 100 bytes using malloc. Somehow I end up using only 40 bytes from this 100 bytes. There are two scenarios..

  1. 40 bytes used are from the front basically,40 60 where 40 is used and 60 is not used.
  2. 40 bytes used are from the back, 60 40 where 40 is used and 60 is not used.

I will always have the pointer that points to this unused memory and the size of the unused memory. I think free cannot be used as it will think it should free 100 bytes. Question is, Is it possible to free 60 bytes of memory from the allocated memory in both scenarios and how?

CodePudding user response:

The function realloc allows you to shrink the size of the allocated memory.

However, in the example in your question, if you use realloc to shrink the array from 100 bytes to 40 bytes, you will keep the first 40 bytes of data and lose the last 60 bytes of data. Therefore, this will only work in scenario #1 of your question.

If you also want it to work in scenario #2, then you will have to first copy the 40 bytes at the back of the memory buffer to the front of the memory buffer, for example using memcpy.

However, some operating systems do provide a way to free the back of a contiguous region of memory, without freeing the front. Examples of this are mmap/mremap on Linux and VirtualFree on Microsoft Windows. But such functions generally work with individual memory pages, which are typically at least 4096 bytes large, so these features will only be useful when dealing with larger amounts of memory. They won't be useful in the example in your question, which only deals with 100 bytes.

The ISO C standard library itself does not provide the functionality mentioned in the previous paragraph. Therefore, if you want your code to remain portable, you will be restricted to using realloc.

CodePudding user response:

realloc can be used to decrease (or increase) the size of an allocation previously returned by malloc, calloc, or realloc.

However, in doing so, the previous pointer value to this memory is invalidated.

realloc resizes the allocation relative to its beginning, so if the data resides towards the end of the allocation, that data must be moved forward.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TOTAL 100
#define USED 40
#define UNUSED 60

int main(void)
{
    int *front_used = calloc(TOTAL, sizeof *front_used);
    memset(front_used, 0, USED * sizeof *front_used);

    int *ftemp = realloc(front_used, USED * sizeof *front_used);
    /* ftemp should be checked for NULL */
    front_used = ftemp;

    int *back_used = calloc(TOTAL, sizeof *back_used);
    memset(back_used   UNUSED, 0, USED * sizeof *back_used);
    /* must move data to start of buffer */
    memmove(back_used, back_used   UNUSED, USED * sizeof *back_used);

    int *btemp = realloc(back_used, USED * sizeof *back_used);
    /* btemp should be checked for NULL */
    back_used = btemp;
}

CodePudding user response:

TLDR: You should never free a partial block of memory. And you shouldn't bother about such small optimizations as they'd rather probably impact your program negatively.

While this thought is common across beginners who are trying to be as precise about memory usage as they can be, it is really not a good idea to do something like this. This is because of how the memory manager works internally.

To give you some idea, let me try to explain it in a rather small context. So, how do you think the memory manager knows how many blocks of memory starting from the given pointer does it need to free?

Most common implementation and the implementation that I am aware of is that the memory manager stores a block of metadata in the byte right before the memory pointed to by the pointer. The metadata includes information that helps the memory manager do its job properly - store what amount of memory is associated with the pointer to next to it, store the location of next available block of free memory etc.

So let's say you allocated 100 bytes of memory the following way:

char* characterPointer = malloc(sizeof(char)*100);

And as mentioned in your question, you use some amount of memory from these 100 slots allocated (say 40).

Now if you try to free a memory beginning at the 41st index, something like the following:

free(characterPointer 40);

The memory manager will step one byte to the left and try to parse whatever bit pattern is present there as the meta data for the given pointer. Now what do you think would happen? Well the answer is even I don't know and it probably depends. But one thing that can be said for sure is it'll lead to some unwanted behaviour.

It might free more memory than you wanted, or less, nevertheless, you would have corrupted the memory. In general, it is ideal to not bother about such small blocks of memory.

Memory manager is built to do something similar. For ex-sometimes, when you ask for 100 bytes of memory, the memory manager might return to a block of memory that is larger than 100 bytes long and this is perfectly okay because it satisfies your memory requirement. Such decisions are made behind the scenes to improve the speed of the manager and they vary from each implementation of a memory manager.

CodePudding user response:

You cannot partially free a block previously allocated by malloc. The closest option you have is to use realloc to resize the memory block previously allocated by malloc.

Also, please be aware that freed blocks of memory do not immediately become available to the operating system. They are listed as free blocks and made accessible to malloc for future allocations, first.

Last but not least, allocating and freeing small chunks of memory can lead to memory fragmentation, which is probably a worse problem than the one you are trying to address.

  •  Tags:  
  • c
  • Related