I noticed that this program:
#include <stdio.h> int main() { const size_t alloc_size = 1*1024*1024; for (size_t i = 0; i < 3; i++) { printf("1n"); usleep(1000*1000); void *p[3]; for (size_t j = 3; j--; ) memset(p[j] = malloc(alloc_size),0,alloc_size); // memset for de-virtualize the memory usleep(1000*1000); printf("2n"); free(p[i]); p[i] = NULL; usleep(1000*1000*4); printf("3n"); for (size_t j = 3; j--; ) free(p[j]); } }
which allocates 3 memories, 3 times and each time frees different memory, frees the memory according to watch free -m
, which means that the OS reclaimed the memory for every free
regardless of the memory’s position inside the program’s address space. Can I somehow get a guarantee for this effect? Or is there already anything like that (like a rule of >64KB
allocations)?
Advertisement
Answer
The short answer is: In general, you cannot guarantee that the OS will reclaim the freed memory, but there may be an OS specific way to do it or a better way to ensure such behavior.
The long answer:
Your code has undefined behavior: there is an extra
free(p[i]);
after theprintf("2n");
which accesses beyond the end of thep
array.You allocate large blocks (1 MB) for which your library makes individual system calls (for example
mmap
in linux systems), andfree
releases these blocks to the OS, hence the observed behavior.Various OSes are likely to implement such behavior for a system specific threshold (typically 128KB), but the C standard gives guarantee about this, so relying on such behavior is system specific.
Read the manual page for
malloc()
on your system to see if this behavior can be controlled. For example, the C library on Linux uses an environment variableMMAP_THRESHOLD
to override the default setting for this threshold.If you program to a Posix target, you might want to use
mmap()
directly instead ofmalloc
to guarantee that the memory is returned to the system once deallocated withmunmap()
. Note that the block returned bymmap()
will have been initialized to all bits zero before the first access, so you may avoid such explicit initialization to take advantage of on demand paging, on perform explicit initialization to ensure the memory is mapped to try and minimize latency in later operations.