malloc
, calloc
, and realloc
These functions are not different allocators. They are different ways of asking for memory from the same allocator.
malloc
provides memory without initializing it (filled with whatever the previous user stored in it).
calloc
is same as malloc
but it will also initialize the memory (fill it with the zero byte 0x00
).
realloc
takes an already allocated memory and allows the users to resize it.
So, in the context of allocators and their different implementations, malloc
, calloc
and realloc
are not listed independently, because each allocator implementation needs its own version of these functions.
jemalloc
, ptmalloc
, ...
When someone wants to implement a different allocator, he can't (can but shouldn't by default) name it malloc
because it will collide with the C standard library one. Instead, they usually give it a different prefix like jemalloc, ptmalloc, nedmalloc, tcmalloc and others.
It is worth mentioning that there are, also, multiple implementations of the C standard library itself and each will implement its allocator differently. So malloc
will have a different implementation based on what standard library being used when compiling the code. Examples are: the GNU C Standard library, MSVC standard library, etc.
What is the difference between different allocators?
To know the exact advantages and disadvantages of each implementation, one must read the documentation written by the author/authors of each one if it exists, read the code to understand the algorithm or read articles/research papers written by experts that talks about that particular implementation.
However, if I were to categorize the differences between these implementations, I would list the following:
- Some implementations focus on certain usage patterns and try to optimize for them even at expense of decreasing efficiency of other cases. An example for this would be
jemalloc
where they focused on optimizing allocation from multiple threads to make it faster but at the expense of using more memory. These types of allocators typically deployed upon careful investigation of a specific case that showed it will benefits from this trade-off.
- Some implementations put a certain limitation on the usage of the allocator in order to make it faster. An example is single-threaded allocators which will eliminate the need for synchronization objects to make it faster.
- Other implementations try to be as general-purpose as possible and doesn't favor any case over the others. This category includes the default allocators that is included in the standard libraries.