Saturday, September 8, 2012

Memory allocation upon malloc() in C

Hi All,
Many of you would have already known how memory allocation happens when malloc() function is used in C language. This article is just the gist of my study on malloc() function.

What happens when you invoke malloc()?
When the C compiler sees malloc(4) function in the program, it requests the underlying OS (Operating System) to allocate 4 bytes and the OS, upon allocation, returns the block containing the address to the next block in the memory + the starting address of the memory allocated + the size of the block (here 4 bytes), rounded off to the multiples of size of the most restricted datatype on the machine.

Example:
int *p;
p=(int*)malloc(sizeof(int));
printf("%u\n",p);
p=(int*)malloc(sizeof(int));
printf("%u\n",p);
p=(int*)malloc(sizeof(int));
printf("%u\n",p);
p=(int*)malloc(sizeof(int));
printf("%u\n",p);
returns...

152002568
152002584
152002600
152002616
These are separated by 16 bytes, on my 32-bit machine! Please find the math for this below.
I will try to illustrate it with another bigger example there and put math of both examples together.


What is the most restrictive datatype?
For each machine, there is a most restrictive type. It is not unique and varies on different machines. It means that if you can store the most restricted datatype in an address, you can store any primitive type. Generally it will be double (as it is on my machine) but I read somewhere that it can be int or float too.

Yet another example, with calculations?
Consider creating the following structure and allocate memory using malloc() function.
struct test
{
char c;
char f;
int a;
int b;
float d;
double e;
double g;
double h;
double i;
};
int main()
{
struct test *t;
t=(struct test*)malloc(sizeof(struct test));
printf("%d\n",sizeof(struct test));
printf("%u\n",t);
t=(struct test*)malloc(sizeof(struct test));
printf("%u\n",t);
t=(struct test*)malloc(sizeof(struct test));
printf("%u\n",t);
t=(struct test*)malloc(sizeof(struct test));
printf("%u\n",t);
t=(struct test*)malloc(sizeof(struct test));
printf("%u\n",t);
t=(struct test*)malloc(sizeof(struct test));
printf("%u\n",t);
return 0;
}
returns...
48
140615688
140615744
140615800
140615856
140615912
140615968
Reason goes here...
On a 32-bit machine, char occupies 1 byte, int and float, 4 bytes while double occupies 8 bytes. So the structure essentially needs 46 bytes but 48 bytes are allocated because it should be in the multiples of (8 bytes - most restricted datatype, double on a 32-bit machine).
Now, on a 32-bit machine, each word is addressed by 32 bits (==4 bytes). So, as per the explanation given above w.r.t. block returned by malloc(), it has to return the address to next block (4 bytes) + address of allocated block (4 bytes) + size of structure (48 bytes), i.e. 56 bytes. This is the reason why we got addresses separated by 56 bytes for each allocation!

Similar math follows for the first example I quoted...
On a 32-bit machine, int occupies 4 bytes, but address to the next block (4 bytes) and address of the currently allocated block (4 bytes) add up to it making it 12 bytes. But the actual memory allocated must be in the multiples of most restricted datatype on the underlying machine which is double ( 8 bytes) and hence 16 bytes are allocated.

Hope this information will be useful to you all. I would like to have your comments/feedback on this. I am open for discussion on this topic! :)

6 comments:

  1. Excellent! Thanks for providing us with such valuable information. No where you/we can find these details :)

    ReplyDelete
    Replies
    1. Thanks Aashish. It was your doubt which made me do this little research! :)

      Delete
  2. good one bhayya...
    but whats the actual purpose of storing the next block address??

    ReplyDelete
    Replies
    1. As far as my understanding goes, it depends upon implementation by different Operating Systems.
      Essentially malloc is designed to contain 2 addresses (1 of the next block and 1 of the current) plus the size, rounded off to the nearest multiple of the size of maximum restricted datatype.
      Different OSes implement it differently; few may even have some dummy padding bits too.
      Using malloc essentially accounts for a lot of overhead in many OSes!

      Delete
  3. Hi Kausal,

    Nice blog .. the examples are very helpful in understanding the concepts ..
    Could you please explain how to find out the most restricted datatype on a given machine? I ve a 64 bit machine and my addr are separated by 64 bytes ..I need to know the most restricted datatype in my machine to explain the results im getting..

    Thanks in advance,
    Megha

    ReplyDelete
    Replies
    1. Hi Megha,
      Firstly, sorry for late reply. I somehow missed your comment and have just seen you have asked a question.
      Most restricted datatype, in my understanding has to be found experimentally. You can try creating a structure like I did in this example and check how much size (in what multiples) is getting allocated and it should give you an idea about it. Try two or three different structures and you should know the most restricted datatype on your machine.
      As such, I think there is no direct way to find it.
      Let me know if you have any issues in this regard.

      Thanks.

      Delete