I am observing the following behavior in my test program:
I am doing malloc()
for 1 MB and then free()
it after sleep(10)
. I am doing this five times. I am observing memory consumption in top
while the program is running.
Once free()
-d, I am expecting the program's virtual memory (VIRT) consumption to be down by 1 MB. But actually it isn't. It stays stable. What is the explanation for this behavior? Does malloc()
do some reserve while allocating memory?
This is very dependent on the actual malloc implementation in use.
Under Linux, there is a threshold (
MMAP_THRESHOLD
) to decide where the memory for a givenmalloc()
request comes from.If the requested amount is below or equal to
MMAP_THRESHOLD
, the request is satisfied by either taking it from the so-called "free list", if any memory blocks have already beenfree()
d. Otherwise, the "break line" of the program (i. e. the end of the data segment) is increased and the memory made available to the program by this process is used for the request.On
free()
, the freed memory block is added to the free list. If there is enough free memory at the very end of the data segment, the break line (mentionned above) is moved again to shrink the data segment, returning the excess memory to the OS.If the requested amount exceeds
MMAP_THRESHOLD
, a separate memory block is requested by the OS and returned again duringfree()
.See also https://linux.die.net/man/3/malloc for details.
Well, this is not guaranteed by the C standard. It only says, once you
free()
the memory, you should not be accessing that any more.Whether the memory block is actually returned to the available memory pool or kept aside for future allocations is decided by the memory manager.
The C standard doesn't force on the implementer of
malloc
andfree
to return the memory to the OS directly. So different C library implementations will behave differently. Some of them might give it back directly and some might not. In fact, the same implementation will also behave differently depending on the allocation sizes and patterns.This behavior, of course, is for good reasons:
In most cases, you are not accountable for the memory you
free
if the implementation decided to keep it (assuming it is a good implementation). Sooner or later it will be reallocated or returned to the OS. Hence, optimizing for memory usage should be based on the amount you havemalloc
-ed and you haven'tfree
-d. The case where you have to worry about this, is when your allocation patterns/sizes start causing memory fragmentation which is a very big topic on its own.If you are, however, on an embedded system and the amount of memory available is limited and you need more control over when/how memory is allocated and freed then you need to ask for memory pages from the OS directly and manage it manually.
Edit: I did not explain why you are not accountable for memory you free. The reason is, on a modern OS, allocated memory is virtual. Meaning if you allocate 512MB on 32-bit system or 10TB of 64-bit system, as long as you don't read or write to that memory, it will not reserve any physical space for it. Actually, it will only reserve physical memory for the pages you touch from that big block and not the entire block. And after "a while of not using that memory", its contents will be copied to disk and the underlying physical memory will be used for something else.