2

I have the following code:

int main()
{
   char * str1 = (char*)malloc(101 * sizeof(char));
   for (int i=0; i<100; i++)
   {
      str1[i] = 'b';
   }
   str1[100] = 0;

   char * str2 = (char*)malloc(1001 * sizeof(char));
   for (int i=0; i<1000; i++)
   {
      str2[i] = 'a';
   }
   str2[1000] = 0;


   for (int i=0; i<7000; i++)
   {
      char * tmp = str2;
      str2 = (char*) malloc((strlen(str2) + strlen(str1) + 1) * sizeof(char));
      sprintf(str2, "%s%s", tmp, str1);
      free(tmp);
   }

   free(str1);
   free(str2);
}

When running it, task manager reports the following Memory Usage: beginning of the program - 1056K , end of the program - 17,748K

To my knowledge there are no memory leaks and I compiled it without debug symbols (release mode).

Any ideas why this might happen?

Tim Post
  • 33,371
  • 15
  • 110
  • 174
mihai
  • 37,072
  • 9
  • 60
  • 86

3 Answers3

10

I think this is because free doesn't have to return memory to the OS. It simply returns it to the free pool, from where it can be allocated by malloc.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • 1
    When you allocate more memory than the OS has designated for your program, the OS increases the amount of memory available for your program to use. The amount available doesn't necessarily go back down when you free the memory. – N_A Aug 24 '11 at 14:41
  • Yes, this behavior is entirely defined by the implementation of the VMM on any given host. All `free()` does is indicate that the memory is no longer needed. This is one of the reasons why operating on dangling pointers results in undefined behavior. – Tim Post Aug 24 '11 at 14:46
  • Hmm, this seems to be in line with the behaviour I noticed while debugging...the mem usage doesn't increase each time I call malloc, but from time to time. – mihai Aug 24 '11 at 14:48
  • 1
    I think this also has to do with malloc size. If I write a program that does malloc/free with the same size, nothing happens. If I change the malloc size at every iteration, I get increased memory usage at the end. – mihai Aug 24 '11 at 15:18
3

This is probably an artifact of how malloc selects from the available pools of memory to satisfy a malloc. Also, tools like TaskManager and top (for unix) are notoriously bad at providing an indication of actual memory used by a process. Every time one of my customers gives me a top output and tells me my process is leaking, I cringe because now I have to prove that it is not.

Lou
  • 1,955
  • 14
  • 16
1

malloc is a memory management function provided by the C standard library. When your program calls malloc it is not directly allocating memory from the operating system. Malloc implementations generally have a pool of memory which they carve up into blocks to satisfy allocation requests. When you call free you are only giving your memory block back to this memory pool.

Repeated calls to malloc will eventually allocate all of the memory from the memory pool managed by the standard library. At this point a system call will need to be made to get more memory from the operating system. On linux this is the brk system call, there will no doubt be something similar on Windows.

The Task Manager in Windows, or top in linux, will report the amount of memory that the operating system has allocated to your process. This will normally be more than the amount of memory your program has allocated via malloc.

If you ltrace a program on linux you can see these malloc and brk calls being made

ltrace -S <some program>
malloc(65536 <unfinished ...>
SYS_brk(NULL)                = 0x2584000
SYS_brk(0x25b5000)           = 0x25b5000
SYS_brk(NULL)                = 0x25b5000
<... malloc resumed> )       = 0x2584010

In this example we try to malloc(65536), but the malloc system does not have enough free memory to satisfy this request. So it calls the brk() system call to get more memory from the operating system. After this call completes it can resume the malloc call and give the program the memory it requested.