Need info on malloc trace

cgccmallocmemory

When I try the below code I am not clearly able to analyze malloc api internal calls.What I am not clear is about the system call mmap is called only once for 2 or more malloc calls.If I am assigning more then 4069 bytes also it is calling only one mmap internally(trace is identified by using strace -p processid ).

#include<stdio.h>
#include<stdlib.h>

main()
{
int *p,*q;
sleep(20);
p=malloc(5096);
printf("p=%p\n",p);
q=malloc(4096);
printf("q=%p\n",q);
sleep(2);
return 0;
}

strace OUTPUT:

root@TEST:/home/harish# strace  -p 6109
Process 6109 attached
restart_syscall(<... resuming interrupted call ...>
) = 0
brk(0)                                  = 0xeca000
brk(0xeec000)                           = 0xeec000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f10b7bc7000
write(1, "p=0xeca010\n", 11)            = 11
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({20, 0},
0x7ffc34a51790)      = 0
write(1, "q=0xecb020\n", 11)            = 11
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({2, 0}, 0x7ffc34a51790)       = 0
exit_group(0)                           = ?
+++ exited with 0 +++

What I am looking is ,if malloc is used more then once will it call more then one mmap since memory is exceeding in two malloc's beyond 4096

Best Answer

If you really want to understand malloc internals, look into the source code. On Linux systems it is likely to be in GNU libc but there are other implementations of the C standard library (the musl-libc source code is nice to read) and of malloc (e.g. tcmalloc). Here is a very fast and simple malloc, but completely useless since always failing.

Grossly speaking, malloc is always built above operating system primitives (i.e. system calls, for Linux listed in syscalls(2)) modifying the virtual address space. Concretely that means mostly mmap(2) & munmap(2) (and perhaps also the obsolete sbrk(2), etc...) on Linux.

The OS kernel is managing the virtual address space by pages (often 4Kbytes on x86) using the MMU. Hence the page size is defined by the hardware.

The implementation of malloc & free can be tricky. First, it obviously won't mmap an entire page of 4Kbytes for every small malloc (of e.g. 24 or 32 bytes), since that would waste space. So it would call mmap once in a while, and organize the obtained pages wisely. Then, it probably would mmap a large segment (of many consecutive pages) for large allocations (e.g. some malloc of two megabytes). It also tries to reuse previously free-d memory zones, because calling mmap is much slower than an ordinary function call.

So most malloc-s handles at least differently small zones and larges ones, and some malloc-s are even more clever. The lib would for example manage a linked list of small zones of same size, and to get the initial space for that it might mmap one or several consecutive pages. Then, free-ing such small zones is adding the free-d zone to that linked list. So most small malloc-s won't use mmap but simply get an element for such lists. For large zones the implementation might mmap and munmap each of them. Some implementations of malloc are keeping the size of the zone in some word just before the zone.

In the details, the implementation is doing considerably more tricky things (i.e. don't use lists, but tries, use several regions or arenas, could allocate tiny mallocs of two words in specific address ranges, etc...). You can find many research papers on malloc (because there are many trade-offs to consider), and several tutorials, e.g. this. Read also about fragmentation & garbage collection (sometimes using the Boehm conservative GC is worthwhile in C programs: you would use GC_MALLOC instead of malloc and you won't care about calling free), e.g. read the GC handbook.

GNU libc provides mallinfo(3), malloc_info(3), mallopt(3), mcheck(3) etc. The valgrind program is very useful to hunt memory leaks and corruptions.

BTW, you might use strace(1) (and perhaps also ltrace(1) ...) directly:

strace ./yourprog

PS. My answer is focused on Linux. On other OSes the details are different.

Related Topic