9

I am writing OS independent lockless queue, so far it works great, but there is small problem with memory managment. I am not sure if its gcc problem or mine. Problem: Memory increases when element is added to list, but when element is removed from list (free(elementPointer);) memory usage don't change.

BUT when I use pthreads, N producers and M consumers (1<N<20, 1<M<20) memory usage is about ~10mb all the time (when trying to add and remove ~10kk elements), so looks like free is working.

And funny thing is that in VS 2010 (same code, no threads) free works fine, memory is released (watched task manager).

I made test, added 1kk elements, after adding all, removed one by one all elements (no threads).

Linux - 0.08 seconds

Windows ~57 seconds

Linux(without free) - 0.07 seconds

Windows(without free) - 0.9 seconds

So, the question is, why memory isn't freed in Linux C when no threads are used ? I can post code if necessary .

GCC version: 4.4.3

Rob
  • 14,746
  • 28
  • 47
  • 65
Full_Int
  • 319
  • 4
  • 13

3 Answers3

11

On many operating systems, free() doesn't make the memory available for the OS again, but "only" for new calls to malloc(). This is why you don't see the memory usage go down externally, but when you increase the number of new allocations by threading, the memory is re-used so total usage doesn't go through the roof.

unwind
  • 391,730
  • 64
  • 469
  • 606
8

Malloc doesn't have to return memory to the operating system. Most malloc implementations on unix-like systems don't do it. Especially for smaller object sizes.

This is done for performance reasons.

I just noticed that this is potentially unclear. By "malloc" I mean the whole subsystem related to the malloc function - malloc, free, realloc, calloc and whatever special functions your libc might implement.

Art
  • 19,807
  • 1
  • 34
  • 60
  • The syscalls used to change the address space are `mmap` and `munmap` (and `mprotect`) on Linux. They are expensive, and the address space can only change in page-size (typically 4Kbytes) granularity. `malloc`+`free` implementation try to reuse memory when possible. – Basile Starynkevitch Nov 05 '12 at 13:18
  • @BasileStarynkevitch You forgot sbrk which is also used to allocate more memory to a process. – fuz Nov 05 '12 at 13:49
  • I think that `sbrk` is less and less used by recent `malloc` implementations, in particular because it is probably less thread friendly, and because of address space layout randomization. – Basile Starynkevitch Nov 05 '12 at 13:51
  • @BasileStarynkevitch On Linux with normal glibc, malloc allocates its memory from the kernel with brk for all allocations below 128kB. Try it with strace. – Art Nov 05 '12 at 13:57
  • 1
    @Art depends on the setting in mallopt(M_MMAP_THRESHOLD), but by default its 128k. An actual call to malloc on x64 (with the default), its (128*1024)-23 that is the first allocation which calls mmap(), -24 still calls sbrk(). Just FEI – Rahly Sep 22 '16 at 01:24
5

To oversimplify things, there are two memory managers at work in dynamic memory allocation: the OS Memory Manager, and the Process Memory Manager (which there can be more than one of). The OS Memory Manager allocates "large chunks" of memory to individual Process Memory Managers. Each Process Memory Manager keeps track of the allocated segments, as well as the "free'd segments". The Process Memory Manager does not return the free'd segments to the OS Memory Manager because it is more efficient to hold on to it, in case it needs to allocate more memory later.

Nocturno
  • 9,579
  • 5
  • 31
  • 39