For glibc malloc()
, read the man 3 malloc
man page.
In short, smaller allocations use memory provided by sbrk()
to extend the data segment; this is not returned to the OS. Larger allocations (typically 132 KiB or more; you can use MMAP_THRESHOLD
on glibc to change the limit) use mmap()
to allocate anonymous memory pages (but also include memory allocation bookkeeping on those pages), and when freed, these are usually immediately returned to the OS.
The only case when you should worry about the process returning memory to the OS in a timely manner, is if you have a long-running process, that temporarily does a very large allocation, running on an embedded or otherwise memory-constrained device. Why? Because this stuff has been done in C successfully for decades, and the C library and the OS kernel do handle these cases just fine. It just isn't a practical problem in normal circumstances. You only need to worry about it, if you know it is a practical problem; and it won't be a practical problem except on very specific circumstances.
I personally do routinely use mmap(2)
in Linux to map pages for huge data sets. Here, "huge" means "too large to fit in RAM and swap".
Most common case is when I have a truly huge binary data set. Then, I create a (sparse) backing file of suitable size, and memory-map that file. Years ago, in another forum, I showed an example of how to do this with a terabyte data set -- yes, 1,099,511,627,776 bytes -- of which only 250 megabytes or so was actually manipulated in that example, to keep the data file small. The key here in this approach is to use MAP_SHARED | MAP_NORESERVE
to ensure the kernel does not use swap memory for this dataset (because it would be insufficient, and fail), but use the file backing directly. We can use madvise()
to inform the kernel of our probable access patterns as an optimization, but in most cases it does not have that big of an effect (as the kernel heuristics do a pretty good job of it anyway). We can also use msync()
to ensure certain parts are written to storage. (There are certain effects that has wrt. other processes that read the file backing the mapping, especially depending on whether they read it normally, or use options like O_DIRECT
; and if shared over NFS or similar, wrt. processes reading the file remotely. It all goes quite complicated very quickly.)
If you do decide to use mmap()
to acquire anonymous memory pages, do note that you need to keep track of both the pointer and the length (length being a multiple of page size, sysconf(_SC_PAGESIZE)
), so that you can release the mapping later using munmap()
. Obviously, this is then completely separate from normal memory allocation (malloc()
, calloc()
, free()
); but unless you try to use specific addresses, the two will not interfere with each other.